source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_bond.cpp@ 16bd37

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 16bd37 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: 13.0 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_bond.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_bond.hpp"
37
38#include <Qt3D/qglmaterial.h>
39#include <Qt3D/qglscenenode.h>
40
41#include "CodePatterns/MemDebug.hpp"
42
43
44#include <cmath>
45
46#include "CodePatterns/Assert.hpp"
47#include "CodePatterns/Log.hpp"
48#include "CodePatterns/Observer/Notification.hpp"
49#include "CodePatterns/Observer/ObserverLog.hpp"
50#include "Descriptors/AtomIdDescriptor.hpp"
51#include "Atom/atom.hpp"
52#include "Bond/bond.hpp"
53#include "Element/element.hpp"
54#include "Helpers/defs.hpp"
55#include "LinearAlgebra/Line.hpp"
56#include "LinearAlgebra/Vector.hpp"
57#include "World.hpp"
58
59#include "ObservedValue_wCallback.hpp"
60
61
62// static entities
63const Observable::channels_t
64GLMoleculeObject_bond::BondPositionChannels(1, AtomObservable::PositionChanged);
65const Observable::channels_t
66GLMoleculeObject_bond::BondDegreeChannels(1, BondObservable::DegreeChanged);
67const Observable::channels_t
68GLMoleculeObject_bond::BondElementChannels(1, AtomObservable::ElementChanged);
69
70GLMoleculeObject_bond::GLMoleculeObject_bond(
71 QGLSceneNode *mesh[],
72 QObject *parent,
73 const bondIds_t bondIds,
74 const enum SideOfBond side) :
75 GLMoleculeObject(mesh, parent),
76 Observer(std::string("GLMoleculeObject_bond")
77 +toString(bondIds.first)
78 +std::string("-")
79 +toString(bondIds.second)),
80 leftatomId(bondIds.first),
81 rightatomId(bondIds.second),
82 leftowner(getAtom(leftatomId)),
83 rightowner(getAtom(rightatomId)),
84 bondowner(getAtom(leftatomId)->getBond(getAtom(rightatomId)).get()),
85 BondSide(side),
86 ObservedValues(MAX_ObservedTypes),
87 subjectKilledCount(0),
88 leftobservable_enabled(false),
89 rightobservable_enabled(false)
90{
91 initObservedValues();
92
93 // sign on as observer (obtain non-const instance before)
94 bondowner->signOn(this, BondObservable::BondRemoved);
95 bondowner->signOn(this, BondObservable::DegreeChanged);
96 bond_enabled = true;
97 leftowner->signOn(this, AtomObservable::PositionChanged);
98 leftowner->signOn(this, AtomObservable::ElementChanged);
99 leftobservable_enabled = true;
100 rightowner->signOn(this, AtomObservable::PositionChanged);
101 rightowner->signOn(this, AtomObservable::ElementChanged);
102 rightobservable_enabled = true;
103
104 resetElement();
105 resetPosition();
106 resetWidth();
107
108 connect(this, SIGNAL(elementChanged()), this, SLOT(resetElement()), Qt::QueuedConnection);
109 connect(this, SIGNAL(positionChanged()), this, SLOT(resetPosition()), Qt::QueuedConnection);
110 connect(this, SIGNAL(degreeChanged()), this, SLOT(resetWidth()), Qt::QueuedConnection);
111}
112
113GLMoleculeObject_bond::~GLMoleculeObject_bond()
114{
115 LOG(3, "DEBUG: Destroying GLMoleculeObject_bond to bond [" <<
116 leftatomId << "," << rightatomId << "] and side " << BondSide << ".");
117 // signOff() if not already done
118 removeChannels();
119 destroyObservedValues();
120}
121
122void GLMoleculeObject_bond::removeChannels()
123{
124 // at this point both atoms should still be alive, hence we may safely sign off
125 // from the AtomObservable itself
126 if (bond_enabled) {
127 if (bondowner != NULL) {
128 bondowner->signOff(this, BondObservable::BondRemoved);
129 bondowner->signOff(this, BondObservable::DegreeChanged);
130 }
131 bond_enabled = false;
132 }
133 if (leftobservable_enabled) {
134 if (leftowner != NULL) {
135 leftowner->signOff(this, AtomObservable::PositionChanged);
136 leftowner->signOff(this, AtomObservable::ElementChanged);
137 }
138 leftobservable_enabled = false;
139 }
140 if (rightobservable_enabled) {
141 if (rightowner != NULL) {
142 rightowner->signOff(this, AtomObservable::PositionChanged);
143 rightowner->signOff(this, AtomObservable::ElementChanged);
144 }
145 rightobservable_enabled = false;
146 }
147}
148
149void GLMoleculeObject_bond::update(Observable *publisher)
150{
151 ASSERT(0, "GLMoleculeObject_bond::update() - we are not signed on for any global updates.");
152}
153
154void GLMoleculeObject_bond::subjectKilled(Observable *publisher)
155{
156 // we signOff from all other sources
157 removeChannels();
158 // check whether we should be removed
159 countsubjectKilled();
160}
161
162void GLMoleculeObject_bond::recieveNotification(Observable *publisher, Notification_ptr notification)
163{
164#ifdef LOG_OBSERVER
165 if (publisher == static_cast<const Observable *>(bondowner)) {
166 observerLog().addMessage() << "++ Update of Observer "
167 << observerLog().getName(static_cast<Observer*>(this))
168 << " received notification from bond for channel "
169 << notification->getChannelNo() << ".";
170 } else if (publisher == static_cast<const Observable * const>(leftowner)) {
171 observerLog().addMessage() << "++ Update of Observer "
172 << observerLog().getName(static_cast<Observer*>(this))
173 << " received notification from leftatom " << leftatomId << " for channel "
174 << notification->getChannelNo() << ".";
175 } else if (publisher == static_cast<const Observable * const>(rightowner)) {
176 observerLog().addMessage() << "++ Update of Observer "
177 << observerLog().getName(static_cast<Observer*>(this))
178 << " received notification from rightatom " << rightatomId << " for channel "
179 << notification->getChannelNo() << ".";
180 }
181#endif
182 if (publisher == static_cast<const Observable *>(bondowner)){
183 switch (notification->getChannelNo()) {
184 case BondObservable::BondRemoved:
185// removeMe();
186 break;
187 case BondObservable::DegreeChanged:
188 emit degreeChanged();
189 break;
190 default:
191 ASSERT(0, "GLMoleculeObject_bond::recieveNotification() - unknown signal.");
192 break;
193 }
194 } else {
195 // from an atom
196 switch (notification->getChannelNo()) {
197 case AtomObservable::PositionChanged:
198 LOG(2, "INFO: Received notification of PositionChanged.");
199 emit positionChanged();
200 break;
201 case AtomObservable::ElementChanged:
202 LOG(2, "INFO: Received notification of ElementChanged.");
203 emit elementChanged();
204 break;
205 default:
206 break;
207 }
208 }
209}
210
211Vector GLMoleculeObject_bond::updateLeftPosition() const
212{
213 const atom * const _atom = getAtomConst(leftatomId);
214 return _atom->getPosition();
215}
216
217Vector GLMoleculeObject_bond::updateRightPosition() const
218{
219 const atom * const _atom = getAtomConst(rightatomId);
220 return _atom->getPosition();
221}
222
223atomicNumber_t GLMoleculeObject_bond::updateLeftElement() const
224{
225 const atom * const _atom = getAtomConst(leftatomId);
226 return _atom->getElementNo();
227}
228
229atomicNumber_t GLMoleculeObject_bond::updateRightElement() const
230{
231 const atom * const _atom = getAtomConst(rightatomId);
232 return _atom->getElementNo();
233}
234
235int GLMoleculeObject_bond::updateDegree() const
236{
237 const atom * const _leftatom = const_cast<const World &>(World::getInstance()).
238 getAtom(AtomById(leftatomId));
239 const atom * const _rightatom = const_cast<const World &>(World::getInstance()).
240 getAtom(AtomById(rightatomId));
241 if ((_leftatom != NULL) && (_rightatom != NULL)) {
242 bond::ptr _bond = _leftatom->getBond(_rightatom);
243 return _bond->getDegree();
244 } else {
245 return 1;
246 }
247}
248
249void GLMoleculeObject_bond::resetElement()
250{
251 size_t elementno = getrightElement();
252 QGLMaterial *elementmaterial = getMaterial(elementno);
253 setMaterial(elementmaterial);
254}
255
256void GLMoleculeObject_bond::resetWidth()
257{
258 const double factor = 1.0f+.5f*(getDegree()-1);
259 LOG(2, "DEBUG: GLMoleculeObject_bond::resetWidth() - setting bond's width to " << factor << ".");
260 setScaleX(factor);
261 setScaleY(factor);
262
263 emit changed();
264}
265
266void GLMoleculeObject_bond::resetPosition()
267{
268 Vector Position = getleftPosition();
269 Vector OtherPosition = getrightPosition();
270 const double distance =
271 Position.distance(OtherPosition)/2.;
272 setScaleZ(distance);
273
274 // calculate position
275 Vector Z(unitVec[2]); // cylinder are initially aligned along the Z axis
276 Vector zeroVec(0.,0.,0.);
277 Vector a,b;
278 Vector OtherAxis;
279 double alpha;
280 a = Position - OtherPosition;
281 // construct rotation axis
282 b = a;
283 b.VectorProduct(Z);
284 Line axis(zeroVec, b);
285 // calculate rotation angle
286 alpha = a.Angle(Z);
287 // construct other axis to check right-hand rule
288 OtherAxis = b;
289 OtherAxis.VectorProduct(Z);
290 // assure right-hand rule for the rotation
291 if (a.ScalarProduct(OtherAxis) < MYEPSILON)
292 alpha = M_PI-alpha;
293 // check
294 Vector a_rotated = axis.rotateVector(a, alpha);
295 LOG(3, "INFO: Created cylinder from "// << Position << " to " << OtherPosition
296 << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively.");
297
298 // set position (cylinder offset is in its barymetric center)
299 Vector OneFourth(Position - 0.75 * a);
300 setPosition(QVector3D(OneFourth[0], OneFourth[1], OneFourth[2]));
301 setRotationVector(QVector3D(b[0], b[1], b[2]));
302 setRotationAngle(alpha/M_PI*180.);
303
304 emit changed();
305}
306
307atom * const GLMoleculeObject_bond::getAtom(const atomId_t _id)
308{
309 atom * const _atom = World::getInstance().getAtom(AtomById(_id));
310 return _atom;
311}
312
313const atom * const GLMoleculeObject_bond::getAtomConst(const atomId_t _id)
314{
315 const atom * const _atom = const_cast<const World &>(World::getInstance()).
316 getAtom(AtomById(_id));
317 return _atom;
318}
319
320void GLMoleculeObject_bond::countsubjectKilled()
321{
322 ++subjectKilledCount;
323
324 if (subjectKilledCount > ObservedValues.size())
325 emit BondRemoved(leftatomId, rightatomId);
326}
327
328void GLMoleculeObject_bond::initObservedValues()
329{
330 // fill ObservedValues
331 boost::function<void()> subjectKilled =
332 boost::bind(&GLMoleculeObject_bond::countsubjectKilled, this);
333 ObservedValues[leftPosition] = new ObservedValue_wCallback<Vector>(
334 leftowner,
335 boost::bind(&GLMoleculeObject_bond::updateLeftPosition, this),
336 "BondleftPosition_"+toString(leftatomId),
337 updateLeftPosition(),
338 BondPositionChannels,
339 subjectKilled);
340 ObservedValues[rightPosition] = new ObservedValue_wCallback<Vector>(
341 rightowner,
342 boost::bind(&GLMoleculeObject_bond::updateRightPosition, this),
343 "BondrightPosition_"+toString(rightatomId),
344 updateRightPosition(),
345 BondPositionChannels,
346 subjectKilled);
347 ObservedValues[leftElement] = new ObservedValue_wCallback<atomicNumber_t>(
348 leftowner,
349 boost::bind(&GLMoleculeObject_bond::updateLeftElement, this),
350 "BondleftElement"+toString(leftatomId),
351 updateLeftElement(),
352 BondElementChannels,
353 subjectKilled);
354 ObservedValues[rightElement] = new ObservedValue_wCallback<atomicNumber_t>(
355 rightowner,
356 boost::bind(&GLMoleculeObject_bond::updateRightElement, this),
357 "BondrightElement"+toString(rightatomId),
358 updateRightElement(),
359 BondElementChannels,
360 subjectKilled);
361 ObservedValues[Degree] = new ObservedValue_wCallback<int>(
362 bondowner,
363 boost::bind(&GLMoleculeObject_bond::updateDegree, this),
364 "BondDegree"+toString(leftatomId)+"_"+toString(rightatomId),
365 updateDegree(),
366 BondDegreeChannels,
367 subjectKilled);
368}
369
370void GLMoleculeObject_bond::destroyObservedValues()
371{
372 delete boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[leftPosition]);
373 delete boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[rightPosition]);
374 delete boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[leftElement]);
375 delete boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[rightElement]);
376 delete boost::any_cast<ObservedValue_wCallback<int> *>(ObservedValues[Degree]);
377 ObservedValues.clear();
378}
379
380Vector GLMoleculeObject_bond::getleftPosition() const
381{
382 return boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[leftPosition])->get();
383}
384
385Vector GLMoleculeObject_bond::getrightPosition() const
386{
387 return boost::any_cast<ObservedValue_wCallback<Vector> *>(ObservedValues[rightPosition])->get();
388}
389
390atomicNumber_t GLMoleculeObject_bond::getleftElement() const
391{
392 return boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[leftElement])->get();
393}
394
395atomicNumber_t GLMoleculeObject_bond::getrightElement() const
396{
397 return boost::any_cast<ObservedValue_wCallback<atomicNumber_t> *>(ObservedValues[rightElement])->get();
398}
399
400int GLMoleculeObject_bond::getDegree() const
401{
402 return boost::any_cast<ObservedValue_wCallback<int> *>(ObservedValues[Degree])->get();
403}
Note: See TracBrowser for help on using the repository browser.