source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_bond.cpp@ 3e52834

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 3e52834 was 009e2e2, checked in by Frederik Heber <heber@…>, 10 years ago

GLMoleculeObject_bond uses ObservedValue for internally representing atom's state.

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