source: src/UIElements/Views/Qt4/Qt3D/GLWorldScene.cpp@ 9d1a78

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

FIX: GLWorldScene used iterator also in NDEBUG, connect still outside mutex.

  • Property mode set to 100644
File size: 34.1 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 * 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"
39#include <Qt3D/qglview.h>
40#include <Qt3D/qglbuilder.h>
41#include <Qt3D/qglscenenode.h>
42#include <Qt3D/qglsphere.h>
43#include <Qt3D/qglcylinder.h>
44
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
51#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
52
53#include "CodePatterns/MemDebug.hpp"
54
55#include "CodePatterns/Log.hpp"
56
57#include <boost/assign.hpp>
58
59#include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp"
60#include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp"
61#include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp"
62#include "Actions/SelectionAction/Molecules/NotMoleculeByIdAction.hpp"
63#include "Atom/atom.hpp"
64#include "Bond/bond.hpp"
65#include "Descriptors/AtomIdDescriptor.hpp"
66#include "Descriptors/MoleculeIdDescriptor.hpp"
67#include "Helpers/helpers.hpp"
68#include "Shapes/ShapeRegistry.hpp"
69#include "molecule.hpp"
70#include "World.hpp"
71
72#include <iostream>
73
74using namespace MoleCuilder;
75
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
143GLWorldScene::GLWorldScene(
144 QtObservedInstanceBoard * _board,
145 QObject *parent) :
146 QObject(parent),
147 BondNodeParentMaps(std::vector<BondNodeParentMap_t>(2)),
148 selectionMode(SelectAtom),
149 board(_board)
150{
151 qRegisterMetaType<atomId_t>("atomId_t");
152 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
153
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;
158 GLMoleculeObject::meshEmpty[i] = emptyBuilder.finalizedSceneNode();
159 QGLBuilder sphereBuilder;
160 sphereBuilder << QGLSphere(2.0, sphereDetails[i]);
161 GLMoleculeObject::meshSphere[i] = sphereBuilder.finalizedSceneNode();
162 GLMoleculeObject::meshSphere[i]->setOption(QGLSceneNode::CullBoundingBox, true);
163 QGLBuilder cylinderBuilder;
164 cylinderBuilder << QGLCylinder(.25,.25,1.0,cylinderDetails[i]);
165 GLMoleculeObject::meshCylinder[i] = cylinderBuilder.finalizedSceneNode();
166 GLMoleculeObject::meshCylinder[i]->setOption(QGLSceneNode::CullBoundingBox, true);
167 }
168 connect(board, SIGNAL(moleculeInserted(QtObservedMolecule::ptr)),
169 this, SLOT(insertMolecule(QtObservedMolecule::ptr)));
170 connect(board, SIGNAL(moleculeRemoved(ObservedValue_Index_t)),
171 this, SLOT(removeMolecule(ObservedValue_Index_t)));
172
173 connect(board, SIGNAL(atomInserted(QtObservedAtom::ptr)),
174 this, SLOT(connectAtom(QtObservedAtom::ptr)), Qt::DirectConnection);
175 connect(this, SIGNAL(atomConnected(QtObservedAtom::ptr)),
176 this, SLOT(insertAtom(QtObservedAtom::ptr)));
177 connect(board, SIGNAL(atomRemoved(ObservedValue_Index_t)),
178 this, SLOT(removeAtom(ObservedValue_Index_t)));
179
180 connect(board, SIGNAL(bondInserted(QtObservedBond::ptr)),
181 this, SLOT(connectBond(QtObservedBond::ptr)), Qt::DirectConnection);
182 connect(this, SIGNAL(bondConnected(QtObservedBond::ptr)),
183 this, SLOT(insertBond(QtObservedBond::ptr)));
184 connect(board, SIGNAL(bondRemoved(ObservedValue_Index_t)),
185 this, SLOT(removeBond(ObservedValue_Index_t)));
186
187// connect(this, SIGNAL(updated()), this, SLOT(update()));
188}
189
190GLWorldScene::~GLWorldScene()
191{
192 // remove all elements
193 GLMoleculeObject::cleanMaterialMap();
194}
195
196void GLWorldScene::clickAtom(atomId_t no)
197{
198 LOG(3, "INFO: GLWorldScene - atom " << no << " has been clicked.");
199 const atom * const Walker = const_cast<const World &>(World::getInstance()).
200 getAtom(AtomById(no));
201 ASSERT( Walker != NULL,
202 "GLWorldScene::clickAtom() - clicked atom has disappeared.");
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.");
211 molids_t ids(1, mol->getId());
212 if (!World::getInstance().isSelected(mol))
213 SelectionMoleculeById(ids);
214 else
215 SelectionNotMoleculeById(ids);
216 }
217 emit clicked(no);
218}
219
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 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
230
231 connect(_atom.get(), SIGNAL(moleculeChanged()), this, SLOT(reparentAtom()));
232
233 // store the object, as we need it on reparenting
234 const ObservedValue_Index_t atomid = _atom->getIndex();
235#ifndef NDEBUG
236 std::pair< ObservedAtoms_t::iterator, bool > inserter =
237#endif
238 ObservedAtoms.insert( std::make_pair(_atom.get(), _atom) );
239 ASSERT( inserter.second,
240 "GLWorldScene::connectAtom() - observed atom "+toString(_atom)+" already stored?");
241#ifndef NDEBUG
242 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
243#endif
244 ObservedAtomIndexLookup.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) );
251
252 emit atomConnected(_atom);
253}
254
255/** Adds an atom to the scene.
256 *
257 * @param _atom atom to add
258 */
259void GLWorldScene::insertAtom(QtObservedAtom::ptr _atom)
260{
261 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "
262 << _atom->getAtomIndex());
263 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
264
265 const ObservedValue_Index_t atomid = _atom->getIndex();
266 QObject *parent = static_cast<QObject *>(this);
267 GLMoleculeObject_atom *atomObject = NULL;
268 {
269 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(atomid);
270 ASSERT (parentiter != AtomNodeParentMap.left.end(),
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 }
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 }
287#ifndef NDEBUG
288 const AtomNodeMap::iterator iter = AtomsinSceneMap.find(atomid);
289#endif
290 ASSERT(iter == AtomsinSceneMap.end(),
291 "GLWorldScene::insertAtom - same atom with id "
292 +toString(_atom->getAtomIndex())+" added again.");
293 AtomsinSceneMap.insert( make_pair(atomid, atomObject) );
294
295 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(clickAtom(atomId_t)));
296 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
297 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
298 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
299
300 emit changed();
301 emit changeOccured();
302}
303
304template <class T>
305void removeStoredObservedValue(
306 GLWorldScene::ObservedValueIndexLookup_t &_ObservedValueIndexLookup,
307 T &_ObservedValues,
308 const ObservedValue_Index_t &_id)
309{
310 // get QObject* from lookup
311 const GLWorldScene::ObservedValueIndexLookup_t::iterator iter =
312 _ObservedValueIndexLookup.find(_id);
313 ASSERT( iter != _ObservedValueIndexLookup.end(),
314 "removeStoredObservedValue() - could not find index "+toString(_id)
315 +" to stored observed value.");
316 QObject * sender = iter->second;
317 const size_t erased = _ObservedValues.erase(sender);
318 ASSERT( erased == 1,
319 "removeStoredObservedValue() - could not erase stored observed value "
320 +toString(_id));
321 _ObservedValueIndexLookup.erase(iter);
322}
323
324void removeAtomFromScene(
325 GLWorldScene::AtomNodeMap &_AtomsinSceneMap,
326 const ObservedValue_Index_t &_atomid)
327{
328 GLWorldScene::AtomNodeMap::iterator iter = _AtomsinSceneMap.find(_atomid);
329 ASSERT(iter != _AtomsinSceneMap.end(),
330 "removeAtomFromScene() - atom "+toString(_atomid)+" not on display.");
331 GLMoleculeObject_atom *atomObject = iter->second;
332 _AtomsinSceneMap.erase(iter);
333 delete atomObject;
334}
335
336void GLWorldScene::checkAndRemoveAtom(const ObservedValue_Index_t &_atomid)
337{
338 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
339
340 if (checkAtomRemoval(AtomNodeParentMap, ToBeRemovedNodes, _atomid)) {
341 LOG(4, "DEBUG: Found parent of to be removed atom as GLWorldScene, removing.");
342 removeAtomFromScene(AtomsinSceneMap, _atomid);
343 AtomNodeParentMap.left.erase(_atomid);
344 ToBeRemovedNodes.erase(_atomid);
345 removeStoredObservedValue(ObservedAtomIndexLookup, ObservedAtoms, _atomid);
346 }
347}
348
349/** Removes an atom.
350 *
351 * @param _atomid index of the atom that is removed
352 */
353void GLWorldScene::removeAtom(ObservedValue_Index_t _atomid)
354{
355 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atomid)+".");
356 // bonds are removed by signal coming from ~bond
357 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
358
359 ASSERT( ToBeRemovedNodes.count(_atomid) == 0,
360 "GLWorldScene::removeAtom() - removedAtom signal for id "+toString(_atomid)
361 +" came in twice?");
362 ToBeRemovedNodes.insert( _atomid );
363
364 // remove atoms
365 checkAndRemoveAtom( _atomid );
366
367 emit changed();
368 emit changeOccured();
369}
370
371/** Prepares adding a bond to the scene
372 *
373 * We need to listen to moleculeChanged() in order to properly re-parent()
374 * this QObject
375 *
376 * @param _bond bond to connect
377 */
378void GLWorldScene::connectBond(QtObservedBond::ptr _bond)
379{
380 LOG(3, "INFO: GLWorldScene::connectBond() - connecting to bonds " << _bond->getBondIndex());
381
382 connect(_bond.get(), SIGNAL(leftmoleculeChanged()), this, SLOT(reparentBondLeft()), Qt::QueuedConnection);
383 connect(_bond.get(), SIGNAL(rightmoleculeChanged()), this, SLOT(reparentBondRight()), Qt::QueuedConnection);
384
385 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
386
387 // store the object, as we need it on reparenting
388 const ObservedValue_Index_t bondid = _bond->getIndex();
389 {
390#ifndef NDEBUG
391 std::pair< ObservedBonds_t::iterator, bool > inserter =
392#endif
393 ObservedBonds.insert( std::make_pair(_bond.get(), _bond) );
394 ASSERT( inserter.second,
395 "GLWorldScene::connectBond() - observed bond "+toString(_bond)+" already stored?");
396#ifndef NDEBUG
397 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
398#endif
399 ObservedBondIndexLookup.insert( std::make_pair(bondid, _bond.get()) );
400 ASSERT( indexinserter.second,
401 "GLWorldScene::connectBond() - observed bond's index "
402 +toString(bondid)+" already stored?");
403 }
404 {
405 if ((_bond->getLeftAtom() != NULL) && (_bond->getLeftAtom()->getMoleculeRef() != NULL))
406 BondNodeParentMaps[0].left.insert(
407 std::make_pair(bondid, _bond->getLeftAtom()->getMoleculeRef()->getIndex()) );
408 else
409 BondNodeParentMaps[0].left.insert(
410 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
411 if ((_bond->getRightAtom() != NULL) && (_bond->getRightAtom()->getMoleculeRef() != NULL))
412 BondNodeParentMaps[1].left.insert(
413 std::make_pair(bondid, _bond->getRightAtom()->getMoleculeRef()->getIndex()) );
414 else
415 BondNodeParentMaps[1].left.insert(
416 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
417 }
418
419 emit bondConnected(_bond);
420}
421
422/** Adds a bond to the scene.
423 *
424 * @param _bond bond to add
425 */
426void GLWorldScene::insertBond(QtObservedBond::ptr _bond)
427{
428 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
429
430 const std::vector< GLMoleculeObject_bond::SideOfBond > bondsides =
431 boost::assign::list_of<GLMoleculeObject_bond::SideOfBond>
432 (GLMoleculeObject_bond::left)
433 (GLMoleculeObject_bond::right);
434 LOG(3, "INFO: GLWorldScene::insertBond() - Adding bonds " << _bond->getBondIndex());
435
436 const ObservedValue_Index_t bondid = _bond->getIndex();
437#ifdef NDEBUG
438 BondNodeMap::iterator iter = BondsinSceneMap.find(bondid);
439 ASSERT( iter == BondsinSceneMap.end(),
440 "GLWorldScene::insertBond() - bond "+toString(bondid)+" is already known.");
441#endif
442 {
443 for (size_t i=0;i<2;++i) {
444 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[i].left.find(bondid);
445 ASSERT (parentiter != BondNodeParentMaps[i].left.end(),
446 "GLWorldScene::insertBond() - parent to bond id "+toString(bondid)+" unknown?");
447 QObject *parent = this;
448 if (parentiter->second != (ObservedValue_Index_t)NULL) {
449 const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentiter->second);
450 if (moliter != MoleculesinSceneMap.end())
451 parent = moliter->second;
452 }
453
454 GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(
455 GLMoleculeObject::meshCylinder,
456 parent,
457 _bond,
458 bondsides[i]);
459 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
460 BondsinSceneMap.insert( std::make_pair(bondid, bondObject) );
461 }
462 }
463
464 emit changed();
465 emit changeOccured();
466}
467
468void GLWorldScene::checkAndRemoveBond(const ObservedValue_Index_t &_bondid)
469{
470 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
471
472 if (checkBondRemoval(BondNodeParentMaps, ToBeRemovedNodes, _bondid)) {
473 LOG(3, "DEBUG: Found both parents of to be removed bond " << _bondid << " as GLWorldScene, removing.");
474 removeBondFromScene(BondsinSceneMap, _bondid);
475 removeStoredObservedValue(ObservedBondIndexLookup, ObservedBonds, _bondid);
476 eraseBondNodeParents(BondNodeParentMaps, _bondid);
477 ToBeRemovedNodes.erase(_bondid);
478 }
479}
480
481/** Removes a bond.
482 *
483 * @param _bondid id of bond to remove
484 */
485void GLWorldScene::removeBond(ObservedValue_Index_t _bondid)
486{
487 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
488 LOG(3, "INFO: GLWorldScene::removedBond() - got bondRemoved signal from board for id " << _bondid);
489
490 // check current state of associated molecules: We won't receive any
491 // moleculeChanged() here anymore, as this QtObservedBond is already
492 // disconnected from its bond object
493 {
494 const ObservedValueIndexLookup_t::const_iterator objiter = ObservedBondIndexLookup.find(_bondid);
495 ASSERT( objiter != ObservedBondIndexLookup.end(),
496 "GLWorldScene::removeBond() - bond's index "+toString(_bondid)
497 +" to be removed not stored yet?");
498 QObject *obj = objiter->second;
499 const ObservedBonds_t::const_iterator observediter = ObservedBonds.find(obj);
500 ASSERT( observediter != ObservedBonds.end(),
501 "GLWorldScene::removeBond() - bond "+toString(_bondid)
502 +" to be removed not stored yet??");
503 const QtObservedBond::ptr &_bond = observediter->second;
504 if (_bond->getLeftMoleculeIndex() != (moleculeId_t)-1) {
505 BondNodeParentMaps[0].left.erase(_bondid);
506 BondNodeParentMaps[0].left.insert( std::make_pair( _bondid, (ObservedValue_Index_t)NULL) );
507 resetParent(getBondInScene(_bondid, GLMoleculeObject_bond::left), NULL);
508 }
509 if (_bond->getRightMoleculeIndex() != (moleculeId_t)-1) {
510 BondNodeParentMaps[1].left.erase(_bondid);
511 BondNodeParentMaps[1].left.insert( std::make_pair( _bondid, (ObservedValue_Index_t)NULL) );
512 resetParent(getBondInScene(_bondid, GLMoleculeObject_bond::right), NULL);
513 }
514 }
515
516 ASSERT( ToBeRemovedNodes.find(_bondid) == ToBeRemovedNodes.end(),
517 "GLWorldScene::removeBond() - bondRemoved for "+toString(_bondid)+" obtained twice?");
518 ToBeRemovedNodes.insert( _bondid );
519
520 // check whether node has still non-NULL parents, otherwise remove completely
521 checkAndRemoveBond( _bondid );
522
523 emit changed();
524 emit changeOccured();
525}
526
527void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob)
528{
529 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
530 // Find the atom, ob corresponds to.
531 hoverAtomId = -1;
532 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
533 if (atomObject){
534 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
535 if (iter->second == atomObject)
536 hoverAtomId = iter->second->objectId();
537 }
538
539 // Propagate signal.
540 emit hoverChanged(hoverAtomId);
541 } else {
542 // Find the atom, ob corresponds to.
543 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
544 if (moleculeObject){
545 // Propagate signal.
546 emit hoverChanged(moleculeObject->objectId(), 0);
547 }
548 }
549}
550
551void GLWorldScene::clickMolecule(moleculeId_t no)
552{
553 LOG(3, "INFO: GLMoleculeObject_molecule - mol " << no << " has been clicked.");
554 const molecule * const mol= const_cast<const World &>(World::getInstance()).
555 getMolecule(MoleculeById(no));
556 ASSERT(mol, "Atom without molecule has been clicked.");
557 molids_t ids(1, mol->getId());
558 if (!World::getInstance().isSelected(mol))
559 SelectionMoleculeById(ids);
560 else
561 SelectionNotMoleculeById(ids);
562 emit clicked(no);
563}
564
565/** Inserts a molecule into the scene.
566 *
567 * @param _mol molecule to insert
568 */
569void GLWorldScene::insertMolecule(QtObservedMolecule::ptr _mol)
570{
571 const ObservedValue_Index_t molid = _mol->getIndex();
572 LOG(3, "INFO: GLWorldScene: Received signal moleculeInserted for molecule "
573 << _mol->getMolIndex());
574
575 MoleculeNodeMap::const_iterator iter = MoleculesinSceneMap.find(molid);
576 ASSERT( iter == MoleculesinSceneMap.end(),
577 "GLWorldScene::insertMolecule() - molecule's id "+toString(molid)
578 +" already present.");
579
580 // add new object
581 LOG(1, "DEBUG: Adding GLMoleculeObject_molecule to id " << molid);
582 GLMoleculeObject_molecule *molObject =
583 new GLMoleculeObject_molecule(
584 GLMoleculeObject::meshEmpty,
585 this,
586 _mol);
587 ASSERT( molObject != NULL,
588 "GLWorldScene::insertMolecule - could not create molecule object for "
589 +toString(molid));
590#ifndef NDEBUG
591 foreach (QObject *obj, molObject->children()) {
592 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
593 ASSERT( meshobj == NULL,
594 "GLWorldScene::insertMolecule() - there are already atoms or bonds attached to a to molecule.");
595 }
596#endif
597
598 // check all atoms for not yet assigned parents
599 {
600 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
601 std::pair<AtomNodeParentMap_t::right_const_iterator, AtomNodeParentMap_t::right_const_iterator> iters =
602 AtomNodeParentMap.right.equal_range(molid);
603 for (AtomNodeParentMap_t::right_const_iterator iter = iters.first;
604 iter != iters.second; ++iter) {
605 AtomNodeMap::const_iterator atomiter = AtomsinSceneMap.find(iter->second);
606 if (atomiter != AtomsinSceneMap.end())
607 resetParent(atomiter->second, molObject);
608 }
609 }
610 // check all bonds for not yet assigned parents
611 {
612 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
613 for (size_t i=0;i<2;++i) {
614 std::pair<BondNodeParentMap_t::right_const_iterator, BondNodeParentMap_t::right_const_iterator> iters =
615 BondNodeParentMaps[i].right.equal_range(molid);
616 for (BondNodeParentMap_t::right_const_iterator iter = iters.first;
617 iter != iters.second; ++iter) {
618 BondNodeMap::const_iterator bonditer = BondsinSceneMap.find(iter->second);
619 if (bonditer != BondsinSceneMap.end())
620 resetParent(bonditer->second, molObject);
621 }
622 }
623 }
624
625#ifndef NDEBUG
626 std::pair<MoleculeNodeMap::iterator, bool> inserter =
627#endif
628 MoleculesinSceneMap.insert( make_pair(molid, molObject) );
629 ASSERT(inserter.second,
630 "GLWorldScene::insertMolecule() - molecule "+toString(_mol->getMolIndex())
631 +" already present in scene.");
632
633 connect (molObject, SIGNAL(changed()), this, SIGNAL(changed()));
634 connect (molObject, SIGNAL(changeOccured()), this, SIGNAL(changeOccured()));
635
636 emit changed();
637 emit changeOccured();
638}
639
640/** Removes a molecule from the scene.
641 *
642 * @param _molid index of the molecule to remove
643 */
644void GLWorldScene::removeMolecule(ObservedValue_Index_t _molid)
645{
646 LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molid)+".");
647
648 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molid);
649 ASSERT ( iter != MoleculesinSceneMap.end(),
650 "GLWorldScene::removeMolecule() - to be removed molecule "+toString(_molid)
651 +" is already gone.");
652 GLMoleculeObject_molecule *molObject = iter->second;
653 // check for any atoms and bonds still attached to it
654#ifndef NDEBUG
655 foreach (QObject *obj, molObject->children()) {
656 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
657 ASSERT( meshobj == NULL,
658 "GLWorldScene::removeMolecule() - there are still atoms or bonds attached to a to molecule.");
659 }
660#endif
661 // finally, remove molecule
662 delete molObject;
663 MoleculesinSceneMap.erase(iter);
664
665 emit changed();
666 emit changeOccured();
667}
668
669void GLWorldScene::moleculesVisibilityChanged(ObservedValue_Index_t _id, bool _visible)
670{
671 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id);
672 ASSERT( iter != MoleculesinSceneMap.end(),
673 "GLWorldScene::moleculeInserted() - molecule's id "
674 +toString(board->getMoleculeIdToIndex(_id))+" is unknown.");
675
676 GLMoleculeObject_molecule *molObject = iter->second;
677 molObject->setVisible(_visible);
678
679 emit changed();
680 emit changeOccured();
681}
682
683/** This converts safely index into a GLMoleculeObject_molecule.
684 *
685 * \param _MoleculesinSceneMap all present molecules
686 * \param _molid index to look for
687 * \return MolObject or NULL when not found
688 */
689GLMoleculeObject_molecule *GLWorldScene::getMoleculeObject(
690 const ObservedValue_Index_t _molid) const
691{
692 const MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(_molid);
693 if (moliter != MoleculesinSceneMap.end())
694 return moliter->second;
695 else
696 return NULL;
697}
698
699/** Changes the parent of an object in the scene.
700 *
701 * \param _id index of the object whose parent to change
702 * \param _ob new parent
703 */
704void GLWorldScene::reparentAtom()
705{
706 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
707 QObject * origin = sender();
708 if (origin == NULL) {
709 ELOG(1, "Got reparentAtom() with sender being NULL.");
710 return;
711 }
712 ObservedAtoms_t::const_iterator iter = ObservedAtoms.find(origin);
713 ASSERT( iter != ObservedAtoms.end(),
714 "GLWorldScene::reparentAtom() - atom's "+toString(origin)+" is no longer stored?");
715 QtObservedAtom::ptr walker = iter->second;
716 const ObservedValue_Index_t walkerid = walker->getIndex();
717 LOG(4, "DEBUG: GLWorldScene: Received signal moleculeChanged for atom "+toString(walkerid)+".");
718 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(walkerid);
719 ASSERT( parentiter != AtomNodeParentMap.left.end(),
720 "GLWorldScene::reparentAtom() - could not find object to id "+toString(walkerid));
721
722 // change parent entry
723 AtomNodeParentMap.left.erase(parentiter);
724 if (walker->getMoleculeRef() != NULL)
725 AtomNodeParentMap.left.insert( std::make_pair(walkerid, walker->getMoleculeRef()->getIndex()) );
726 else
727 AtomNodeParentMap.left.insert( std::make_pair(walkerid, (ObservedValue_Index_t)NULL) );
728 parentiter = AtomNodeParentMap.left.find(walkerid);
729
730 const AtomNodeMap::iterator atomiter = AtomsinSceneMap.find(walkerid);
731 if (atomiter != AtomsinSceneMap.end())
732 resetParent(atomiter->second, getMoleculeObject(parentiter->second));
733 // else atom does not yet exist
734
735 // check whether node is still shown, otherwise remove completely
736 checkAndRemoveAtom( walkerid );
737}
738
739/** Changes the parent of an left-side bond in the scene.
740 *
741 */
742void GLWorldScene::reparentBondLeft()
743{
744 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
745 QObject * origin = sender();
746 if (origin == NULL) {
747 ELOG(1, "Got reparentBondLeft() with sender being NULL.");
748 return;
749 }
750 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
751 ASSERT( iter != ObservedBonds.end(),
752 "GLWorldScene::reparentBondLeft() - bond "+toString(origin)+" is no longer stored?");
753 QtObservedBond::ptr bond = iter->second;
754 LOG(3, "INFO: GLWorldScene::reparentBondLeft() - Reparenting left side of bond "
755 << bond->getBondIndex() << ".");
756 reparentBond(bond, bond->getLeftAtom(), GLMoleculeObject_bond::left);
757
758 // check whether node is still shown, otherwise remove completely
759 checkAndRemoveBond( bond->getIndex() );
760}
761
762/** Changes the parent of an right-side bond in the scene.
763 *
764 */
765void GLWorldScene::reparentBondRight()
766{
767 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
768 QObject * origin = sender();
769 if (origin == NULL) {
770 ELOG(1, "Got reparentBondRight() with sender being NULL.");
771 return;
772 }
773 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
774 ASSERT( iter != ObservedBonds.end(),
775 "GLWorldScene::reparentBondRight() - bond "+toString(origin)+" is no longer stored?");
776 QtObservedBond::ptr bond = iter->second;
777 LOG(3, "INFO: GLWorldScene::reparentBondRight() - Reparenting right side of bond "
778 << bond->getBondIndex() << ".");
779 reparentBond(bond, bond->getRightAtom(), GLMoleculeObject_bond::right);
780
781 // check whether node is still shown, otherwise remove completely
782 checkAndRemoveBond( bond->getIndex() );
783}
784
785GLMoleculeObject_bond *GLWorldScene::getBondInScene(
786 const ObservedValue_Index_t _bondid,
787 GLMoleculeObject_bond::SideOfBond _side) const
788{
789 std::pair<GLWorldScene::BondNodeMap::const_iterator, GLWorldScene::BondNodeMap::const_iterator> iters =
790 BondsinSceneMap.equal_range(_bondid);
791 ASSERT( std::distance(iters.first, iters.second) >= 1,
792 "GLWorldScene::getBondInScene() - not at least one bond of id "
793 +toString(_bondid)+" present in scene.");
794 for (GLWorldScene::BondNodeMap::const_iterator bonditer = iters.first;
795 bonditer != iters.second; ++bonditer) {
796 if (bonditer->second->BondSide == _side)
797 return bonditer->second;
798 }
799 return NULL;
800}
801
802/** Changes the parent of an object in the scene.
803 *
804 * \param _atom atom of bond whose molecule we are associated to
805 * \param _side side of bond
806 */
807void GLWorldScene::reparentBond(
808 const QtObservedBond::ptr _bond,
809 const QtObservedAtom::ptr _atom,
810 const GLMoleculeObject_bond::SideOfBond _side)
811{
812 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
813 const size_t dim = (_side == GLMoleculeObject_bond::left) ? 0 : 1;
814 const ObservedValue_Index_t bondid = _bond->getIndex();
815 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[dim].left.find(bondid);
816 ASSERT( parentiter != BondNodeParentMaps[dim].left.end(),
817 "GLWorldScene::reparentBond() - could not find object to id "+toString(bondid));
818
819 // change parent entry
820 BondNodeParentMaps[dim].left.erase(bondid);
821 if ((_atom != NULL) && (_atom->getMoleculeRef() != NULL))
822 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, _atom->getMoleculeRef()->getIndex()));
823 else
824 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, (ObservedValue_Index_t)NULL) );
825 parentiter = BondNodeParentMaps[dim].left.find(bondid);
826 LOG(3, "INFO: GLWorldScene::reparentBond() - Reparented bond "
827 << _bond->getBondIndex() << " to " << parentiter->second);
828
829 // reset parent
830 resetParent(getBondInScene(bondid, _side), getMoleculeObject(parentiter->second));
831}
832
833/** Resets the parent of an GLMoleculeObject.
834 *
835 * \param _obj object to reparent
836 * \param _molid index of parent molecule
837 */
838void GLWorldScene::resetParent(
839 GLMoleculeObject *_obj,
840 GLMoleculeObject_molecule *_molobj)
841{
842 if (_obj != NULL) {
843 if (_molobj != NULL) {
844 LOG(5, "DEBUG: Resetting parent of " << _obj << " to " << _molobj);
845 _obj->setParent(_molobj);
846 ASSERT( _obj->parent() == _molobj,
847 "GLWorldScene::resetParent() - new parent "+toString(_molobj)+" was not set.");
848 } else {
849 LOG(5, "DEBUG: Resetting parent of " << _obj << " to " << this);
850 _obj->setParent(this);
851 ASSERT( _obj->parent() == this,
852 "GLWorldScene::resetParent() - new parent "+toString(this)+" was not set.");
853 }
854 } else
855 ELOG(1, "Object to reparent was NULL.");
856 // else object does not yet exist
857}
858
859/** Adds a shape to the scene.
860 *
861 */
862void GLWorldScene::addShape(const std::string &_name)
863{
864 Shape * const shape = ShapeRegistry::getInstance().getByName(_name);
865 if (shape != NULL) {
866 GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(*shape, this);
867 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
868 ASSERT(iter == ShapesinSceneMap.end(),
869 "GLWorldScene::addShape() - same shape "+_name+" added again.");
870 ShapesinSceneMap.insert( make_pair(_name, shapeObject) );
871 } else
872 ELOG(2, "GLWorldScene::addShape() - shape disappeared before we could draw it.");
873
874 emit changed();
875}
876
877void GLWorldScene::removeShape(const std::string &_name)
878{
879 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
880 ASSERT(iter != ShapesinSceneMap.end(),
881 "GLWorldScene::removeShape() - shape "+_name+" not in scene.");
882 ShapesinSceneMap.erase(iter);
883 delete(iter->second);
884
885 emit changed();
886}
887
888void GLWorldScene::updateSelectedShapes()
889{
890 foreach (QObject *obj, children()) {
891 GLMoleculeObject_shape *shapeobj = qobject_cast<GLMoleculeObject_shape *>(obj);
892 if (shapeobj){
893 shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape()));
894 }
895 }
896
897 emit changed();
898}
899
900void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
901{
902 // Initialize all of the mesh objects that we have as children.
903 foreach (QObject *obj, children()) {
904 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
905 if (meshobj)
906 meshobj->initialize(view, painter);
907 }
908}
909
910void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const
911{
912 // Draw all of the mesh objects that we have as children.
913 foreach (QObject *obj, children()) {
914 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
915 if (meshobj)
916 meshobj->draw(painter, cameraPlane);
917 }
918}
919
920void GLWorldScene::setSelectionMode(SelectionModeType mode)
921{
922 selectionMode = mode;
923 // TODO send update to toolbar
924}
925
926void GLWorldScene::setSelectionModeAtom()
927{
928 setSelectionMode(SelectAtom);
929}
930
931void GLWorldScene::setSelectionModeMolecule()
932{
933 setSelectionMode(SelectMolecule);
934}
935
Note: See TracBrowser for help on using the repository browser.