source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.cpp@ 2831b3

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

FIX: All ObservedValue's of GLMoleculeObject_atom/bond/molecule wrapped into vector.

  • the idea is that a GLMoleculeObject may only remove itself _after_ each and every contained Observer has gotten the subjectKilled() signal from the Observables. Only then will destroying the Object and its members thereby not cause any signOff() which try to access Observables or their channels which are no longer present. This can be imagined as a graph where we have to start destroying object at the very bottom.
  • This is the avoid the following conflict: A superior object gets note of a molecule to be removed. It sends the visual representation a signal to remove itself, which causes it to use signOff(). On a parallel track (in another thread) we have the observed object calling subjectKilled() to inform any Observer about its immediate destruction. These two tracks collide. Now, we let first pass all subjectKilled() and when the last Observable has gotten its signal, we begin destroying the visual rep.
  • rerouted signal/slots accordingly.
  • Property mode set to 100644
File size: 12.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 * GLMoleculeObject_atom.cpp
26 *
27 * Created on: Aug 17, 2011
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "GLMoleculeObject_atom.hpp"
37
38#include <Qt3D/qglscenenode.h>
39
40#include "CodePatterns/MemDebug.hpp"
41
42#include "CodePatterns/Assert.hpp"
43#include "CodePatterns/Log.hpp"
44#include "CodePatterns/Observer/Notification.hpp"
45
46#include <algorithm>
47#include <boost/assign.hpp>
48
49#include "Atom/atom.hpp"
50#include "Bond/bond.hpp"
51#include "Descriptors/AtomIdDescriptor.hpp"
52#include "Element/element.hpp"
53#include "Element/periodentafel.hpp"
54#include "LinearAlgebra/Vector.hpp"
55#include "GLMoleculeObject_bond.hpp"
56#include "World.hpp"
57#include "WorldTime.hpp"
58
59#include "ObservedValue_wCallback.hpp"
60
61using namespace boost::assign;
62
63static const Observable::channels_t getAtomBondsChannels()
64{
65 Observable::channels_t channels;
66 channels += AtomObservable::BondsAdded, AtomObservable::BondsRemoved;
67 return channels;
68}
69
70// static entities
71const Observable::channels_t
72GLMoleculeObject_atom::AtomIndexChannels(1, AtomObservable::IndexChanged);
73const Observable::channels_t
74GLMoleculeObject_atom::AtomPositionChannels(1, AtomObservable::PositionChanged);
75const Observable::channels_t
76GLMoleculeObject_atom::AtomElementChannels(1, AtomObservable::ElementChanged);
77const Observable::channels_t
78GLMoleculeObject_atom::AtomBondsChannels(getAtomBondsChannels());
79
80GLMoleculeObject_atom::GLMoleculeObject_atom(QGLSceneNode *mesh[], QObject *parent, const atomId_t _id) :
81 GLMoleculeObject(mesh, parent),
82 Observer(std::string("GLMoleculeObject_atom")+toString(_id)),
83 atomref(getAtom(_id)),
84 ObservedValues(MAX_ObservedTypes),
85 subjectKilledCount(0),
86 owner(NULL)
87{
88 initObservedValues(_id);
89
90 setObjectId(_id);
91 resetPosition();
92 resetElement();
93
94 m_selected = const_cast<const World &>(World::getInstance()).isAtomSelected(_id);
95
96 // sign On
97 activateObserver();
98
99 // atomref is only used for caching the ref, it must be used elswhere
100 const_cast<atom *&>(atomref) = NULL;
101
102 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
103 connect( this, SIGNAL(idChanged()), this, SLOT(resetIndex()), Qt::QueuedConnection);
104 connect( this, SIGNAL(elementChanged()), this, SLOT(resetElement()), Qt::QueuedConnection);
105 connect( this, SIGNAL(positionChanged()), this, SLOT(resetPosition()), Qt::QueuedConnection);
106 connect( this, SIGNAL(bondsChanged()), this, SLOT(resetPosition()), Qt::QueuedConnection);
107}
108
109void GLMoleculeObject_atom::activateObserver()
110{
111 if (atomref != NULL) {
112 owner = static_cast<const Observable *>(atomref);
113 owner->signOn(this, AtomObservable::IndexChanged);
114 owner->signOn(this, AtomObservable::PositionChanged);
115 owner->signOn(this, AtomObservable::ElementChanged);
116 owner->signOn(this, AtomObservable::BondsAdded);
117 owner->signOn(this, AtomObservable::BondsRemoved);
118 }
119}
120
121
122void GLMoleculeObject_atom::deactivateObserver()
123{
124 // sign Off
125 if (owner != NULL) {
126 owner->signOff(this, AtomObservable::IndexChanged);
127 owner->signOff(this, AtomObservable::PositionChanged);
128 owner->signOff(this, AtomObservable::ElementChanged);
129 owner->signOff(this, AtomObservable::BondsAdded);
130 owner->signOff(this, AtomObservable::BondsRemoved);
131 owner = NULL;
132 }
133}
134
135GLMoleculeObject_atom::~GLMoleculeObject_atom()
136{
137 deactivateObserver();
138 destroyObservedValues();
139}
140
141void GLMoleculeObject_atom::resetIndex()
142{
143 const atomId_t newId = getAtomIndex();
144 const size_t oldId = objectId();
145 ASSERT( newId != oldId,
146 "GLMoleculeObject_atom::updateIndex() - index "+toString(newId)+" did not change.");
147 LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(newId)+".");
148 setObjectId(newId);
149
150 emit indexChanged(this, oldId, newId);
151}
152
153void GLMoleculeObject_atom::resetPosition()
154{
155 const Vector Position = getAtomPosition();
156 LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new position is "+toString(Position)+".");
157 setPosition(QVector3D(Position[0], Position[1], Position[2]));
158}
159
160void GLMoleculeObject_atom::resetElement()
161{
162 size_t elementno = 0;
163 const element * const _type = World::getInstance().
164 getPeriode()->FindElement(getAtomElement());
165 if (_type != NULL) {
166 elementno = _type->getAtomicNumber();
167 } else { // if no element yet, set to hydrogen
168 elementno = 1;
169 }
170 LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new element number is "+toString(elementno)+".");
171
172 // set materials
173 QGLMaterial *elementmaterial = getMaterial(elementno);
174 ASSERT(elementmaterial != NULL,
175 "GLMoleculeObject_atom::GLMoleculeObject_atom() - QGLMaterial ref from getter function is NULL.");
176 setMaterial(elementmaterial);
177
178 // set scale
179 double radius = 0.;
180 if (_type != NULL) {
181 radius = _type->getVanDerWaalsRadius();
182 } else {
183 radius = 0.5;
184 }
185 setScale( radius / 4. );
186}
187
188void GLMoleculeObject_atom::resetBonds()
189{
190 ListOfBonds_t ListOfBonds_new = getAtomBonds();
191 std::sort(ListOfBonds_new.begin(), ListOfBonds_new.end());
192 ListOfBonds_t BondsToAdd;
193 std::set_difference(
194 ListOfBonds_new.begin(), ListOfBonds_new.end(),
195 ListOfBonds.begin(), ListOfBonds.end(),
196 std::back_inserter(BondsToAdd));
197 ListOfBonds_t BondsToRemove;
198 std::set_difference(
199 ListOfBonds.begin(), ListOfBonds.end(),
200 ListOfBonds_new.begin(), ListOfBonds_new.end(),
201 std::back_inserter(BondsToRemove));
202 for (ListOfBonds_t::const_iterator iter = BondsToAdd.begin();
203 iter != BondsToAdd.end();
204 ++iter) {
205 const GLMoleculeObject_bond::SideOfBond side = (iter->first == getAtomIndex()) ?
206 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
207 emit BondsAdded(iter->first, iter->second, side);
208 }
209 for (ListOfBonds_t::const_iterator iter = BondsToRemove.begin();
210 iter != BondsToRemove.end();
211 ++iter) {
212 emit BondsRemoved(iter->first, iter->second);
213 }
214 ListOfBonds = ListOfBonds_new;
215}
216
217void GLMoleculeObject_atom::Selected()
218{
219 ASSERT( !m_selected,
220 "GLMoleculeObject_atom::Selected() - 3D rep of atom is already selected.");
221 m_selected = true;
222
223 emit changed();
224}
225
226void GLMoleculeObject_atom::Unselected()
227{
228 ASSERT( m_selected,
229 "GLMoleculeObject_atom::Unselected() - 3D rep of atom is already unselected.");
230 m_selected = false;
231
232 emit changed();
233}
234
235
236void GLMoleculeObject_atom::draw(QGLPainter *painter, const QVector4D &cameraPlane)
237{
238 // call old hook to do the actual paining
239 GLMoleculeObject::draw(painter, cameraPlane);
240}
241
242void GLMoleculeObject_atom::wasClicked()
243{
244 LOG(4, "INFO: GLMoleculeObject_atom: atom " << getAtomIndex() << " has been clicked");
245 emit clicked(getAtomIndex());
246}
247
248const atom * const GLMoleculeObject_atom::getAtomConst(const atomId_t _id)
249{
250 const atom * const _atom = const_cast<const World &>(World::getInstance()).
251 getAtom(AtomById(_id));
252 return _atom;
253}
254
255atom * const GLMoleculeObject_atom::getAtom(const atomId_t _id)
256{
257 atom * const _atom = World::getInstance().getAtom(AtomById(_id));
258 return _atom;
259}
260
261atomId_t GLMoleculeObject_atom::updateIndex() const
262{
263 return const_cast<const World &>(World::getInstance()).lastChangedAtomId();
264}
265
266Vector GLMoleculeObject_atom::updatePosition() const
267{
268 const atom * const _atom = getAtom(getAtomIndex());
269 if (_atom != NULL) {
270 return _atom->getPosition();
271 } else {
272 return zeroVec;
273 }
274}
275
276atomicNumber_t GLMoleculeObject_atom::updateElement() const
277{
278 const atom * const _atom = getAtom(getAtomIndex());
279 if (_atom != NULL) {
280 return _atom->getElementNo();
281 } else {
282 return (atomicNumber_t)-1;
283 }
284}
285
286GLMoleculeObject_atom::ListOfBonds_t GLMoleculeObject_atom::updateBonds() const
287{
288 ListOfBonds_t ListOfBonds;
289 const atom * const _atom = getAtom(getAtomIndex());
290 if (_atom != NULL) {
291 // make sure position is up-to-date
292 const BondList ListBonds = _atom->getListOfBonds();
293 for (BondList::const_iterator iter = ListBonds.begin();
294 iter != ListBonds.end();
295 ++iter)
296 ListOfBonds.insert( ListOfBonds.end(), std::make_pair(
297 (*iter)->leftatom->getId(),
298 (*iter)->rightatom->getId()) );
299 } else {
300 ELOG(2, "Atom with id "+toString(getAtomIndex())+" is already gone.");
301 }
302 return ListOfBonds;
303}
304
305void GLMoleculeObject_atom::update(Observable *publisher)
306{
307 ASSERT(0, "GLMoleculeObject_atom::update() - we are not signed on for global updates.");
308}
309
310void GLMoleculeObject_atom::subjectKilled(Observable *publisher)
311{
312 deactivateObserver();
313
314 countsubjectKilled();
315}
316
317void GLMoleculeObject_atom::recieveNotification(Observable *publisher, Notification_ptr notification)
318{
319 // ObservedValues have been updated before, hence convert updates to Qt's signals
320 atom * const _atom = dynamic_cast<atom *>(publisher);
321 if (_atom != NULL) {
322 switch (notification->getChannelNo()) {
323 case AtomObservable::IndexChanged:
324 emit idChanged();
325 break;
326 case AtomObservable::PositionChanged:
327 emit positionChanged();
328 break;
329 case AtomObservable::ElementChanged:
330 emit elementChanged();
331 break;
332 case AtomObservable::BondsAdded:
333 case AtomObservable::BondsRemoved:
334 emit bondsChanged();
335 break;
336 default:
337 ASSERT(0, "GLMoleculeObject_atom::recieveNotification() - we are not signed on to channel "
338 +toString(notification->getChannelNo())+" of the atom.");
339 break;
340 }
341 } else
342 ASSERT(0, "GLMoleculeObject_atom::recieveNotification() - received notification from unexpected source.");
343}
344
345void GLMoleculeObject_atom::countsubjectKilled()
346{
347 ++subjectKilledCount;
348
349 if (subjectKilledCount > ObservedValues.size())
350 emit InstanceRemoved(getAtomIndex());
351}
352
353void GLMoleculeObject_atom::initObservedValues(const atomId_t _id)
354{
355 // fill ObservedValues
356 boost::function<void()> subjectKilled =
357 boost::bind(&GLMoleculeObject_atom::countsubjectKilled, this);
358 ObservedValues[AtomIndex] = new ObservedValue_wCallback<atomId_t>(
359 atomref,
360 boost::bind(&GLMoleculeObject_atom::updateIndex, this),
361 "AtomIndex_"+toString(_id),
362 _id,
363 AtomIndexChannels,
364 subjectKilled);
365 ObservedValues[AtomPosition] = new ObservedValue_wCallback<Vector>(
366 atomref,
367 boost::bind(&GLMoleculeObject_atom::updatePosition, this),
368 "AtomPosition_"+toString(_id),
369 updatePosition(),
370 AtomPositionChannels,
371 subjectKilled);
372 ObservedValues[AtomElement] = new ObservedValue_wCallback<atomicNumber_t>(
373 atomref,
374 boost::bind(&GLMoleculeObject_atom::updateElement, this),
375 "AtomElement"+toString(_id),
376 updateElement(),
377 AtomElementChannels,
378 subjectKilled);
379 ObservedValues[AtomBonds] = new ObservedValue_wCallback<ListOfBonds_t>(
380 atomref,
381 boost::bind(&GLMoleculeObject_atom::updateBonds, this),
382 "AtomBonds_"+toString(_id),
383 updateBonds(),
384 AtomBondsChannels,
385 subjectKilled);
386}
387
388void GLMoleculeObject_atom::destroyObservedValues()
389{
390 delete boost::any_cast<ObservedValue_wCallback<atomId_t> *>(ObservedValues[AtomIndex]);
391 delete boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[AtomPosition]);
392 delete boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[AtomElement]);
393 delete boost::any_cast<ObservedValue_wCallback<ListOfBonds_t> *>(ObservedValues[AtomBonds]);
394 ObservedValues.clear();
395}
396
397atomId_t GLMoleculeObject_atom::getAtomIndex() const
398{
399 return boost::any_cast<ObservedValue_wCallback<atomId_t> *>(ObservedValues[AtomIndex])->get();
400}
401
402Vector GLMoleculeObject_atom::getAtomPosition() const
403{
404 return boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[AtomPosition])->get();
405}
406
407atomicNumber_t GLMoleculeObject_atom::getAtomElement() const
408{
409 return boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[AtomElement])->get();
410}
411
412GLMoleculeObject_atom::ListOfBonds_t GLMoleculeObject_atom::getAtomBonds() const
413{
414 return boost::any_cast<ObservedValue_wCallback<ListOfBonds_t> *>(ObservedValues[AtomBonds])->get();
415}
Note: See TracBrowser for help on using the repository browser.