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

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

GLWorldScene now holds onto atoms and bonds until ..Removed() signal and parent(s) is reset.

  • Property mode set to 100644
File size: 32.7 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 connect(_atom.get(), SIGNAL(moleculeChanged()), this, SLOT(reparentAtom()));
230
231 // store the object, as we need it on reparenting
232 {
233#ifndef NDEBUG
234 std::pair< ObservedAtoms_t::iterator, bool > inserter =
235#endif
236 ObservedAtoms.insert( std::make_pair(_atom.get(), _atom) );
237 ASSERT( inserter.second,
238 "GLWorldScene::connectAtom() - observed atom "+toString(_atom)+" already stored?");
239#ifndef NDEBUG
240 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
241#endif
242 ObservedValueIndexLookup.insert( std::make_pair(_atom->getIndex(), _atom.get()) );
243 ASSERT( indexinserter.second,
244 "GLWorldScene::connectAtom() - observed atom's index "
245 +toString(_atom->getIndex())+" already stored?");
246 }
247 {
248 const ObservedValue_Index_t atomid = _atom->getIndex();
249 boost::recursive_mutex::scoped_lock lock(AtomNodeParentMap_mutex);
250 AtomNodeParentMap.left.insert( std::make_pair(atomid, (ObservedValue_Index_t)NULL) );
251 }
252
253 emit atomConnected(_atom);
254}
255
256/** Adds an atom to the scene.
257 *
258 * @param _atom atom to add
259 */
260void GLWorldScene::insertAtom(QtObservedAtom::ptr _atom)
261{
262 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "
263 << _atom->getAtomIndex());
264
265 const ObservedValue_Index_t atomid = _atom->getIndex();
266 QObject *parent = static_cast<QObject *>(this);
267 GLMoleculeObject_atom *atomObject = NULL;
268 {
269 boost::recursive_mutex::scoped_lock lock(AtomNodeParentMap_mutex);
270 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(atomid);
271 ASSERT (parentiter != AtomNodeParentMap.left.end(),
272 "GLWorldScene::insertAtom() - parent to atom id "+toString(atomid)+" unknown?");
273 const ObservedValue_Index_t parentindex = parentiter->second;
274 if (parentindex != (ObservedValue_Index_t)NULL) {
275 const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentindex);
276 if (moliter != MoleculesinSceneMap.end())
277 parent = moliter->second;
278 }
279
280 atomObject = new GLMoleculeObject_atom(
281 GLMoleculeObject::meshSphere,
282 parent,
283 _atom);
284 ASSERT( atomObject != NULL,
285 "GLWorldScene::atomInserted - could not create atom object for "
286 +toString(_atom->getAtomIndex()));
287 }
288 AtomNodeMap::iterator iter = AtomsinSceneMap.find(atomid);
289 ASSERT(iter == AtomsinSceneMap.end(),
290 "GLWorldScene::insertAtom - same atom with id "
291 +toString(_atom->getAtomIndex())+" added again.");
292 AtomsinSceneMap.insert( make_pair(atomid, atomObject) );
293
294 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(clickAtom(atomId_t)));
295 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
296 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
297 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
298
299 emit changed();
300 emit changeOccured();
301}
302
303template <class T>
304void removeStoredObservedValue(
305 GLWorldScene::ObservedValueIndexLookup_t &_ObservedValueIndexLookup,
306 T &_ObservedValues,
307 const ObservedValue_Index_t &_id)
308{
309 // get QObject* from lookup
310 const GLWorldScene::ObservedValueIndexLookup_t::iterator iter =
311 _ObservedValueIndexLookup.find(_id);
312 ASSERT( iter != _ObservedValueIndexLookup.end(),
313 "removeStoredObservedValue() - could not find index "+toString(_id)
314 +" to stored observed value.");
315 QObject * sender = iter->second;
316 const size_t erased = _ObservedValues.erase(sender);
317 ASSERT( erased == 1,
318 "removeStoredObservedValue() - could not erase stored observed value "
319 +toString(_id));
320 _ObservedValueIndexLookup.erase(iter);
321}
322
323void removeAtomFromScene(
324 GLWorldScene::AtomNodeMap &_AtomsinSceneMap,
325 const ObservedValue_Index_t &_atomid)
326{
327 GLWorldScene::AtomNodeMap::iterator iter = _AtomsinSceneMap.find(_atomid);
328 ASSERT(iter != _AtomsinSceneMap.end(),
329 "removeAtomFromScene() - atom "+toString(_atomid)+" not on display.");
330 GLMoleculeObject_atom *atomObject = iter->second;
331 _AtomsinSceneMap.erase(iter);
332 delete atomObject;
333}
334
335void GLWorldScene::checkAndRemoveAtom(const ObservedValue_Index_t &_atomid)
336{
337 boost::recursive_mutex::scoped_lock lock(AtomNodeParentMap_mutex);
338
339 if (checkAtomRemoval(AtomNodeParentMap, ToBeRemovedNodes, _atomid)) {
340 LOG(4, "DEBUG: Found parent of to be removed atom as GLWorldScene, removing.");
341 removeAtomFromScene(AtomsinSceneMap, _atomid);
342 AtomNodeParentMap.left.erase(_atomid);
343 ToBeRemovedNodes.erase(_atomid);
344 removeStoredObservedValue(ObservedValueIndexLookup, ObservedAtoms, _atomid);
345 }
346}
347
348/** Removes an atom.
349 *
350 * @param _atomid index of the atom that is removed
351 */
352void GLWorldScene::removeAtom(ObservedValue_Index_t _atomid)
353{
354 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atomid)+".");
355 // bonds are removed by signal coming from ~bond
356
357 ASSERT( ToBeRemovedNodes.count(_atomid) == 0,
358 "GLWorldScene::removeAtom() - removedAtom signal for id "+toString(_atomid)
359 +" came in twice?");
360 ToBeRemovedNodes.insert( _atomid );
361
362 // remove atoms
363 checkAndRemoveAtom( _atomid );
364
365 emit changed();
366 emit changeOccured();
367}
368
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{
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);
382
383 // store the object, as we need it on reparenting
384 {
385#ifndef NDEBUG
386 std::pair< ObservedBonds_t::iterator, bool > inserter =
387#endif
388 ObservedBonds.insert( std::make_pair(_bond.get(), _bond) );
389 ASSERT( inserter.second,
390 "GLWorldScene::connectBond() - observed bond "+toString(_bond)+" already stored?");
391#ifndef NDEBUG
392 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
393#endif
394 ObservedValueIndexLookup.insert( std::make_pair(_bond->getIndex(), _bond.get()) );
395 ASSERT( indexinserter.second,
396 "GLWorldScene::connectBond() - observed bond's index "
397 +toString(_bond->getIndex())+" already stored?");
398 }
399 {
400 const ObservedValue_Index_t bondid = _bond->getIndex();
401 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
402 if ((_bond->getLeftAtom() != NULL) && (_bond->getLeftAtom()->getMoleculeRef() != NULL))
403 BondNodeParentMaps[0].left.insert(
404 std::make_pair(bondid, _bond->getLeftAtom()->getMoleculeRef()->getIndex()) );
405 else
406 BondNodeParentMaps[0].left.insert(
407 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
408 if ((_bond->getRightAtom() != NULL) && (_bond->getRightAtom()->getMoleculeRef() != NULL))
409 BondNodeParentMaps[1].left.insert(
410 std::make_pair(bondid, _bond->getRightAtom()->getMoleculeRef()->getIndex()) );
411 else
412 BondNodeParentMaps[1].left.insert(
413 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
414 }
415
416 emit bondConnected(_bond);
417}
418
419/** Adds a bond to the scene.
420 *
421 * @param _bond bond to add
422 */
423void GLWorldScene::insertBond(QtObservedBond::ptr _bond)
424{
425 static const std::vector< GLMoleculeObject_bond::SideOfBond > bondsides =
426 boost::assign::list_of<GLMoleculeObject_bond::SideOfBond>
427 (GLMoleculeObject_bond::left)
428 (GLMoleculeObject_bond::right);
429 LOG(3, "INFO: GLWorldScene::insertBond() - Adding bonds " << _bond->getBondIndex());
430
431 const ObservedValue_Index_t bondid = _bond->getIndex();
432#ifdef NDEBUG
433 BondNodeMap::iterator iter = BondsinSceneMap.find(bondid);
434 ASSERT( iter == BondsinSceneMap.end(),
435 "GLWorldScene::insertBond() - bond "+toString(bondid)+" is already known.");
436#endif
437 {
438 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
439 for (size_t i=0;i<2;++i) {
440 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[i].left.find(bondid);
441 ASSERT (parentiter != BondNodeParentMaps[i].left.end(),
442 "GLWorldScene::insertBond() - parent to bond id "+toString(bondid)+" unknown?");
443 QObject *parent = this;
444 if (parentiter->second != (ObservedValue_Index_t)NULL) {
445 const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentiter->second);
446 if (moliter != MoleculesinSceneMap.end())
447 parent = moliter->second;
448 }
449
450 GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(
451 GLMoleculeObject::meshCylinder,
452 parent,
453 _bond,
454 bondsides[i]);
455 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
456 BondsinSceneMap.insert( std::make_pair(bondid, bondObject) );
457 }
458 }
459
460 emit changed();
461 emit changeOccured();
462}
463
464void GLWorldScene::checkAndRemoveBond(const ObservedValue_Index_t &_bondid)
465{
466 if (checkBondRemoval(BondNodeParentMaps, ToBeRemovedNodes, _bondid)) {
467 LOG(3, "DEBUG: Found both parents of to be removed bond " << _bondid << " as GLWorldScene, removing.");
468 removeBondFromScene(BondsinSceneMap, _bondid);
469 removeStoredObservedValue(ObservedValueIndexLookup, ObservedBonds, _bondid);
470 eraseBondNodeParents(BondNodeParentMaps, _bondid);
471 ToBeRemovedNodes.erase(_bondid);
472 }
473}
474
475/** Removes a bond.
476 *
477 * @param _bondid id of bond to remove
478 */
479void GLWorldScene::removeBond(ObservedValue_Index_t _bondid)
480{
481 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
482 LOG(3, "INFO: GLWorldScene::removedBond() - got bondRemoved signal from board for id " << _bondid);
483
484 ASSERT( ToBeRemovedNodes.find(_bondid) == ToBeRemovedNodes.end(),
485 "GLWorldScene::removeBond() - bondRemoved for "+toString(_bondid)+" obtained twice?");
486 ToBeRemovedNodes.insert( _bondid );
487
488 // check whether node has still non-NULL parents, otherwise remove completely
489 checkAndRemoveBond( _bondid );
490
491 emit changed();
492 emit changeOccured();
493}
494
495void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob)
496{
497 // Find the atom, ob corresponds to.
498 hoverAtomId = -1;
499 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
500 if (atomObject){
501 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
502 if (iter->second == atomObject)
503 hoverAtomId = iter->second->objectId();
504 }
505
506 // Propagate signal.
507 emit hoverChanged(hoverAtomId);
508 } else {
509 // Find the atom, ob corresponds to.
510 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
511 if (moleculeObject){
512 // Propagate signal.
513 emit hoverChanged(moleculeObject->objectId(), 0);
514 }
515 }
516}
517
518void GLWorldScene::clickMolecule(moleculeId_t no)
519{
520 LOG(3, "INFO: GLMoleculeObject_molecule - mol " << no << " has been clicked.");
521 const molecule * const mol= const_cast<const World &>(World::getInstance()).
522 getMolecule(MoleculeById(no));
523 ASSERT(mol, "Atom without molecule has been clicked.");
524 molids_t ids(1, mol->getId());
525 if (!World::getInstance().isSelected(mol))
526 SelectionMoleculeById(ids);
527 else
528 SelectionNotMoleculeById(ids);
529 emit clicked(no);
530}
531
532/** Inserts a molecule into the scene.
533 *
534 * @param _mol molecule to insert
535 */
536void GLWorldScene::insertMolecule(QtObservedMolecule::ptr _mol)
537{
538 const ObservedValue_Index_t molid = _mol->getIndex();
539 LOG(3, "INFO: GLWorldScene: Received signal moleculeInserted for molecule "
540 << _mol->getMolIndex());
541
542 MoleculeNodeMap::const_iterator iter = MoleculesinSceneMap.find(molid);
543 ASSERT( iter == MoleculesinSceneMap.end(),
544 "GLWorldScene::insertMolecule() - molecule's id "+toString(molid)
545 +" already present.");
546
547 // add new object
548 LOG(1, "DEBUG: Adding GLMoleculeObject_molecule to id " << molid);
549 GLMoleculeObject_molecule *molObject =
550 new GLMoleculeObject_molecule(
551 GLMoleculeObject::meshEmpty,
552 this,
553 _mol);
554 ASSERT( molObject != NULL,
555 "GLWorldScene::insertMolecule - could not create molecule object for "
556 +toString(molid));
557#ifndef NDEBUG
558 foreach (QObject *obj, molObject->children()) {
559 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
560 ASSERT( meshobj == NULL,
561 "GLWorldScene::insertMolecule() - there are already atoms or bonds attached to a to molecule.");
562 }
563#endif
564
565 // check all atoms for not yet assigned parents
566 {
567 boost::recursive_mutex::scoped_lock lock(AtomNodeParentMap_mutex);
568 std::pair<AtomNodeParentMap_t::right_const_iterator, AtomNodeParentMap_t::right_const_iterator> iters =
569 AtomNodeParentMap.right.equal_range(molid);
570 for (AtomNodeParentMap_t::right_const_iterator iter = iters.first;
571 iter != iters.second; ++iter) {
572 AtomNodeMap::const_iterator atomiter = AtomsinSceneMap.find(iter->second);
573 if (atomiter != AtomsinSceneMap.end())
574 resetParent(atomiter->second, molObject);
575 }
576 }
577 // check all bonds for not yet assigned parents
578 {
579 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
580 for (size_t i=0;i<2;++i) {
581 std::pair<BondNodeParentMap_t::right_const_iterator, BondNodeParentMap_t::right_const_iterator> iters =
582 BondNodeParentMaps[i].right.equal_range(molid);
583 for (BondNodeParentMap_t::right_const_iterator iter = iters.first;
584 iter != iters.second; ++iter) {
585 BondNodeMap::const_iterator bonditer = BondsinSceneMap.find(iter->second);
586 if (bonditer != BondsinSceneMap.end())
587 resetParent(bonditer->second, molObject);
588 }
589 }
590 }
591
592#ifndef NDEBUG
593 std::pair<MoleculeNodeMap::iterator, bool> inserter =
594#endif
595 MoleculesinSceneMap.insert( make_pair(molid, molObject) );
596 ASSERT(inserter.second,
597 "GLWorldScene::insertMolecule() - molecule "+toString(_mol->getMolIndex())
598 +" already present in scene.");
599
600 connect (molObject, SIGNAL(changed()), this, SIGNAL(changed()));
601 connect (molObject, SIGNAL(changeOccured()), this, SIGNAL(changeOccured()));
602
603 emit changed();
604 emit changeOccured();
605}
606
607/** Removes a molecule from the scene.
608 *
609 * @param _molid index of the molecule to remove
610 */
611void GLWorldScene::removeMolecule(ObservedValue_Index_t _molid)
612{
613 LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molid)+".");
614
615 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molid);
616 ASSERT ( iter != MoleculesinSceneMap.end(),
617 "GLWorldScene::removeMolecule() - to be removed molecule "+toString(_molid)
618 +" is already gone.");
619 GLMoleculeObject_molecule *molObject = iter->second;
620 // check for any atoms and bonds still attached to it
621#ifndef NDEBUG
622 foreach (QObject *obj, molObject->children()) {
623 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
624 ASSERT( meshobj == NULL,
625 "GLWorldScene::removeMolecule() - there are still atoms or bonds attached to a to molecule.");
626 }
627#endif
628 // finally, remove molecule
629 delete molObject;
630 MoleculesinSceneMap.erase(iter);
631
632 emit changed();
633 emit changeOccured();
634}
635
636void GLWorldScene::moleculesVisibilityChanged(ObservedValue_Index_t _id, bool _visible)
637{
638 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id);
639 ASSERT( iter != MoleculesinSceneMap.end(),
640 "GLWorldScene::moleculeInserted() - molecule's id "
641 +toString(board->getMoleculeIdToIndex(_id))+" is unknown.");
642
643 GLMoleculeObject_molecule *molObject = iter->second;
644 molObject->setVisible(_visible);
645
646 emit changed();
647 emit changeOccured();
648}
649
650/** This converts safely index into a GLMoleculeObject_molecule.
651 *
652 * \param _MoleculesinSceneMap all present molecules
653 * \param _molid index to look for
654 * \return MolObject or NULL when not found
655 */
656GLMoleculeObject_molecule *GLWorldScene::getMoleculeObject(
657 const ObservedValue_Index_t _molid) const
658{
659 const MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(_molid);
660 if (moliter != MoleculesinSceneMap.end())
661 return moliter->second;
662 else
663 return NULL;
664}
665
666/** Changes the parent of an object in the scene.
667 *
668 * \param _id index of the object whose parent to change
669 * \param _ob new parent
670 */
671void GLWorldScene::reparentAtom()
672{
673 boost::recursive_mutex::scoped_lock lock(AtomNodeParentMap_mutex);
674 QObject * origin = sender();
675 if (origin == NULL) {
676 ELOG(1, "Got reparentAtom() with sender being NULL.");
677 return;
678 }
679 ObservedAtoms_t::const_iterator iter = ObservedAtoms.find(origin);
680 ASSERT( iter != ObservedAtoms.end(),
681 "GLWorldScene::reparentAtom() - atom's "+toString(origin)+" is no longer stored?");
682 QtObservedAtom::ptr walker = iter->second;
683 const ObservedValue_Index_t walkerid = walker->getIndex();
684 LOG(4, "DEBUG: GLWorldScene: Received signal moleculeChanged for atom "+toString(walkerid)+".");
685 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(walkerid);
686 ASSERT( parentiter != AtomNodeParentMap.left.end(),
687 "GLWorldScene::reparentAtom() - could not find object to id "+toString(walkerid));
688
689 // change parent entry
690 AtomNodeParentMap.left.erase(parentiter);
691 if (walker->getMoleculeRef() != NULL)
692 AtomNodeParentMap.left.insert( std::make_pair(walkerid, walker->getMoleculeRef()->getIndex()) );
693 else
694 AtomNodeParentMap.left.insert( std::make_pair(walkerid, (ObservedValue_Index_t)NULL) );
695 parentiter = AtomNodeParentMap.left.find(walkerid);
696
697 const AtomNodeMap::iterator atomiter = AtomsinSceneMap.find(walkerid);
698 if (atomiter != AtomsinSceneMap.end())
699 resetParent(atomiter->second, getMoleculeObject(parentiter->second));
700 // else atom does not yet exist
701
702 // check whether node is still shown, otherwise remove completely
703 checkAndRemoveAtom( walkerid );
704}
705
706/** Changes the parent of an left-side bond in the scene.
707 *
708 */
709void GLWorldScene::reparentBondLeft()
710{
711 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
712 QObject * origin = sender();
713 if (origin == NULL) {
714 ELOG(1, "Got reparentBondLeft() with sender being NULL.");
715 return;
716 }
717 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
718 ASSERT( iter != ObservedBonds.end(),
719 "GLWorldScene::reparentBondLeft() - bond "+toString(origin)+" is no longer stored?");
720 QtObservedBond::ptr bond = iter->second;
721 LOG(3, "INFO: GLWorldScene::reparentBondLeft() - Reparenting left side of bond "
722 << bond->getBondIndex() << ".");
723 reparentBond(bond, bond->getLeftAtom(), GLMoleculeObject_bond::left);
724
725 // check whether node is still shown, otherwise remove completely
726 checkAndRemoveBond( bond->getIndex() );
727}
728
729/** Changes the parent of an right-side bond in the scene.
730 *
731 */
732void GLWorldScene::reparentBondRight()
733{
734 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
735 QObject * origin = sender();
736 if (origin == NULL) {
737 ELOG(1, "Got reparentBondRight() with sender being NULL.");
738 return;
739 }
740 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
741 ASSERT( iter != ObservedBonds.end(),
742 "GLWorldScene::reparentBondRight() - bond "+toString(origin)+" is no longer stored?");
743 QtObservedBond::ptr bond = iter->second;
744 LOG(3, "INFO: GLWorldScene::reparentBondRight() - Reparenting right side of bond "
745 << bond->getBondIndex() << ".");
746 reparentBond(bond, bond->getRightAtom(), GLMoleculeObject_bond::right);
747
748 // check whether node is still shown, otherwise remove completely
749 checkAndRemoveBond( bond->getIndex() );
750}
751
752GLMoleculeObject_bond *GLWorldScene::getBondInScene(
753 const ObservedValue_Index_t _bondid,
754 GLMoleculeObject_bond::SideOfBond _side) const
755{
756 std::pair<GLWorldScene::BondNodeMap::const_iterator, GLWorldScene::BondNodeMap::const_iterator> iters =
757 BondsinSceneMap.equal_range(_bondid);
758 ASSERT( std::distance(iters.first, iters.second) >= 1,
759 "GLWorldScene::getBondInScene() - not at least one bond of id "
760 +toString(_bondid)+" present in scene.");
761 for (GLWorldScene::BondNodeMap::const_iterator bonditer = iters.first;
762 bonditer != iters.second; ++bonditer) {
763 if (bonditer->second->BondSide == _side)
764 return bonditer->second;
765 }
766 return NULL;
767}
768
769/** Changes the parent of an object in the scene.
770 *
771 * \param _atom atom of bond whose molecule we are associated to
772 * \param _side side of bond
773 */
774void GLWorldScene::reparentBond(
775 const QtObservedBond::ptr _bond,
776 const QtObservedAtom::ptr _atom,
777 const GLMoleculeObject_bond::SideOfBond _side)
778{
779 boost::recursive_mutex::scoped_lock lock(BondNodeParentMap_mutex);
780 const size_t dim = (_side == GLMoleculeObject_bond::left) ? 0 : 1;
781 const ObservedValue_Index_t bondid = _bond->getIndex();
782 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[dim].left.find(bondid);
783 ASSERT( parentiter != BondNodeParentMaps[dim].left.end(),
784 "GLWorldScene::reparentBond() - could not find object to id "+toString(bondid));
785
786 // change parent entry
787 BondNodeParentMaps[dim].left.erase(bondid);
788 if ((_atom != NULL) && (_atom->getMoleculeRef() != NULL))
789 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, _atom->getMoleculeRef()->getIndex()));
790 else
791 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, (ObservedValue_Index_t)NULL) );
792 parentiter = BondNodeParentMaps[dim].left.find(bondid);
793 LOG(3, "INFO: GLWorldScene::reparentBond() - Reparented bond "
794 << _bond->getBondIndex() << " to " << parentiter->second);
795
796 // reset parent
797 resetParent(getBondInScene(bondid, _side), getMoleculeObject(parentiter->second));
798}
799
800/** Resets the parent of an GLMoleculeObject.
801 *
802 * \param _obj object to reparent
803 * \param _molid index of parent molecule
804 */
805void GLWorldScene::resetParent(
806 GLMoleculeObject *_obj,
807 GLMoleculeObject_molecule *_molobj)
808{
809 if (_obj != NULL) {
810 QObject *parent = this;
811 if (_molobj != NULL)
812 parent = _molobj;
813 // else: molecule does not yet exist: is done when molecule is instantiated
814 LOG(5, "DEBUG: Resetting parent of " << _obj << " to " << parent);
815 _obj->setParent(parent);
816 ASSERT( _obj->parent() == parent,
817 "GLWorldScene::resetParent() - new parent "+toString(parent)+" was not set.");
818 } else
819 ELOG(1, "Object to reparent was NULL.");
820 // else object does not yet exist
821}
822
823/** Adds a shape to the scene.
824 *
825 */
826void GLWorldScene::addShape(const std::string &_name)
827{
828 Shape * const shape = ShapeRegistry::getInstance().getByName(_name);
829 if (shape != NULL) {
830 GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(*shape, this);
831 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
832 ASSERT(iter == ShapesinSceneMap.end(),
833 "GLWorldScene::addShape() - same shape "+_name+" added again.");
834 ShapesinSceneMap.insert( make_pair(_name, shapeObject) );
835 } else
836 ELOG(2, "GLWorldScene::addShape() - shape disappeared before we could draw it.");
837
838 emit changed();
839}
840
841void GLWorldScene::removeShape(const std::string &_name)
842{
843 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
844 ASSERT(iter != ShapesinSceneMap.end(),
845 "GLWorldScene::removeShape() - shape "+_name+" not in scene.");
846 ShapesinSceneMap.erase(iter);
847 delete(iter->second);
848
849 emit changed();
850}
851
852void GLWorldScene::updateSelectedShapes()
853{
854 foreach (QObject *obj, children()) {
855 GLMoleculeObject_shape *shapeobj = qobject_cast<GLMoleculeObject_shape *>(obj);
856 if (shapeobj){
857 shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape()));
858 }
859 }
860
861 emit changed();
862}
863
864void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
865{
866 // Initialize all of the mesh objects that we have as children.
867 foreach (QObject *obj, children()) {
868 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
869 if (meshobj)
870 meshobj->initialize(view, painter);
871 }
872}
873
874void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const
875{
876 // Draw all of the mesh objects that we have as children.
877 foreach (QObject *obj, children()) {
878 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
879 if (meshobj)
880 meshobj->draw(painter, cameraPlane);
881 }
882}
883
884void GLWorldScene::setSelectionMode(SelectionModeType mode)
885{
886 selectionMode = mode;
887 // TODO send update to toolbar
888}
889
890void GLWorldScene::setSelectionModeAtom()
891{
892 setSelectionMode(SelectAtom);
893}
894
895void GLWorldScene::setSelectionModeMolecule()
896{
897 setSelectionMode(SelectMolecule);
898}
899
Note: See TracBrowser for help on using the repository browser.