source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp@ 026bef

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

Changed GLMoleculeObject_...:countSubjectKilled() to taking id parameter.

  • this is a precursor for when the ObservedValues reside with QtInstanceInformationBoard.
  • enhanced ObservedValue_wCallback to take a bound getIndex function().
  • additionally, we route internally to ObservedValue::get() and this gets us out of the painful situation where we need to supply an index getter to the ObservedValue that monitors the index (and hence must be present already to bind to its get function).
  • Property mode set to 100644
File size: 34.5 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_molecule.cpp
26 *
27 * Created on: Mar 30, 2012
28 * Author: ankele
29 */
30
31
32// include config.h
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "GLMoleculeObject_molecule.hpp"
38
39#include <Qt3D/qglscenenode.h>
40#include <Qt3D/qglbuilder.h>
41
42#include "CodePatterns/MemDebug.hpp"
43
44#include <boost/assign.hpp>
45
46#include "CodePatterns/Assert.hpp"
47#include "CodePatterns/Log.hpp"
48#include "CodePatterns/Observer/Notification.hpp"
49#include "CodePatterns/Observer/ObserverLog.hpp"
50
51#include "Atom/atom.hpp"
52#include "molecule.hpp"
53#include "Descriptors/AtomIdDescriptor.hpp"
54#include "Descriptors/MoleculeIdDescriptor.hpp"
55#include "Element/element.hpp"
56#include "LinearAlgebra/Vector.hpp"
57#include "LinkedCell/PointCloudAdaptor.hpp"
58#include "LinkedCell/linkedcell.hpp"
59#include "Tesselation/tesselation.hpp"
60#include "Tesselation/BoundaryLineSet.hpp"
61#include "Tesselation/BoundaryTriangleSet.hpp"
62#include "Tesselation/CandidateForTesselation.hpp"
63#include "Atom/TesselPoint.hpp"
64#include "World.hpp"
65
66#include "ObservedValue_wCallback.hpp"
67#include "ObservedValue_UpdateAtoms.hpp"
68
69using namespace boost::assign;
70
71#include "GLMoleculeObject_atom.hpp"
72
73static Observable::channels_t getAtomsChannels()
74{
75 Observable::channels_t channels;
76 channels += molecule::AtomInserted, molecule::AtomRemoved;
77 return channels;
78}
79
80static Observable::channels_t getAllAtomicChangesChannels()
81{
82 Observable::channels_t channels;
83 channels += molecule::AtomInserted, molecule::AtomRemoved, molecule::AtomMoved;
84 return channels;
85}
86
87// static instances
88const Observable::channels_t GLMoleculeObject_molecule::AtomsChannels(getAtomsChannels());
89const Observable::channels_t GLMoleculeObject_molecule::HullChannels(getAllAtomicChangesChannels());
90const Observable::channels_t GLMoleculeObject_molecule::BoundingBoxChannels(1, molecule::BoundingBoxChanged);
91const Observable::channels_t GLMoleculeObject_molecule::IndexChannels(1, molecule::IndexChanged);
92const Observable::channels_t GLMoleculeObject_molecule::NameChannels(1, molecule::MoleculeNameChanged);
93
94static QGLSceneNode *createMoleculeMesh(const QGeometryData &_geo)
95{
96 // Build a mesh from the geometry.
97 QGLBuilder builder;
98 builder.addTriangles(_geo);
99 QGLSceneNode *mesh = builder.finalizedSceneNode();
100 return mesh;
101}
102
103GLMoleculeObject_molecule::GLMoleculeObject_molecule(QObject *parent, const moleculeId_t _molid) :
104 GLMoleculeObject((QGLSceneNode *)NULL, parent),
105 Observer(std::string("GLMoleculeObject_molecule")+toString(_molid)),
106 owner(NULL),
107 molref(getMolecule(_molid)),
108 /* We must not use boost::cref(this) as "this" has not been properly constructed and seemingly
109 * boost::cref tries to do some magic to grasp the inheritance hierarchy which fails because
110 * the class has not been fully constructed yet. "This" itself seems to be working fine.
111 */
112 ObservedValues(MAX_ObservedTypes),
113 subjectKilledCount(0),
114 TesselationHullUpdater(
115 boost::bind(&GLMoleculeObject_molecule::updateTesselationHull, this)
116 ),
117 TesselationHull(
118 molref,
119 TesselationHullUpdater,
120 "MoleculeTesselationHull_"+toString(_molid),
121 HullChannels),
122 hoverAtomId(-1)
123{
124 boost::function<void(const moleculeId_t)> subjectKilled =
125 boost::bind(&GLMoleculeObject_molecule::countsubjectKilled, this, _molid);
126 initObservedValues(ObservedValues, _molid, molref, subjectKilled);
127
128 setObjectId(_molid);
129 setMaterial(getMaterial(1));
130
131 m_selected = const_cast<const World &>(World::getInstance()).isMoleculeSelected(_molid);
132
133 // initially, atoms and bonds should be visible
134 m_visible = false;
135
136 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
137 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
138 connect (this, SIGNAL(TesselationHullChanged()), this, SLOT(resetTesselationHull()), Qt::QueuedConnection);
139 connect (this, SIGNAL(BoundingBoxChanged()), this, SLOT(resetBoundingBox()), Qt::QueuedConnection);
140 connect (this, SIGNAL(IdChanged()), this, SLOT(resetIndex()), Qt::QueuedConnection);
141 connect (this, SIGNAL(AtomInserted(const atomId_t)), this, SLOT(atomInserted(const atomId_t)), Qt::QueuedConnection);
142 connect (this, SIGNAL(AtomInserted(const atomId_t)), this, SLOT(resetAtoms()), Qt::QueuedConnection);
143 connect (this, SIGNAL(AtomRemoved(const atomId_t)), this, SLOT(resetAtoms()), Qt::QueuedConnection);
144 connect (this, SIGNAL(AtomRemoved(const atomId_t)), this, SLOT(atomRemoved(const atomId_t)), Qt::QueuedConnection);
145
146 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
147}
148
149GLMoleculeObject_molecule::GLMoleculeObject_molecule(
150 QGLSceneNode *mesh[],
151 QObject *parent,
152 const moleculeId_t _molid) :
153 GLMoleculeObject(mesh, parent),
154 Observer(std::string("GLMoleculeObject_molecule")+toString(_molid)),
155 owner(NULL),
156 molref(getMolecule(_molid)),
157 /* We must not use boost::cref(this) as "this" has not been properly constructed and seemingly
158 * boost::cref tries to do some magic to grasp the inheritance hierarchy which fails because
159 * the class has not been fully constructed yet. "This" itself seems to be working fine.
160 */
161 ObservedValues(MAX_ObservedTypes),
162 subjectKilledCount(0),
163 TesselationHullUpdater(
164 boost::bind(&GLMoleculeObject_molecule::updateTesselationHull, this)
165 ),
166 TesselationHull(
167 molref,
168 TesselationHullUpdater,
169 "MoleculeTesselationHull_"+toString(_molid),
170 HullChannels),
171 hoverAtomId(-1)
172{
173 boost::function<void(const moleculeId_t)> subjectKilled =
174 boost::bind(&GLMoleculeObject_molecule::countsubjectKilled, this, _molid);
175 initObservedValues(ObservedValues, _molid, molref, subjectKilled);
176
177 setObjectId(_molid);
178 setMaterial(getMaterial(1));
179
180 m_selected = const_cast<const World &>(World::getInstance()).isMoleculeSelected(_molid);
181
182 // initially, atoms and bonds should be visible
183 m_visible = false;
184
185 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
186 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
187 connect (this, SIGNAL(TesselationHullChanged()), this, SLOT(resetTesselationHull()), Qt::QueuedConnection);
188 connect (this, SIGNAL(BoundingBoxChanged()), this, SLOT(resetBoundingBox()), Qt::QueuedConnection);
189 connect (this, SIGNAL(IdChanged()), this, SLOT(resetIndex()), Qt::QueuedConnection);
190 connect (this, SIGNAL(AtomInserted(const atomId_t)), this, SLOT(atomInserted(const atomId_t)), Qt::QueuedConnection);
191 connect (this, SIGNAL(AtomInserted(const atomId_t)), this, SLOT(resetAtoms()), Qt::QueuedConnection);
192 connect (this, SIGNAL(AtomRemoved(const atomId_t)), this, SLOT(resetAtoms()), Qt::QueuedConnection);
193 connect (this, SIGNAL(AtomRemoved(const atomId_t)), this, SLOT(atomRemoved(const atomId_t)), Qt::QueuedConnection);
194
195 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
196}
197
198GLMoleculeObject_molecule::~GLMoleculeObject_molecule()
199{
200 deactivateObserver();
201 destroyObservedValues(ObservedValues);
202}
203
204void GLMoleculeObject_molecule::deactivateObserver()
205{
206 if (owner != NULL) {
207 owner->signOff(this, molecule::AtomInserted);
208 owner->signOff(this, molecule::AtomRemoved);
209 owner->signOff(this, molecule::AtomMoved);
210 owner->signOff(this, molecule::IndexChanged);
211 owner = NULL;
212 }
213}
214
215void GLMoleculeObject_molecule::activateObserver()
216{
217 // sign on as observer (obtain non-const instance before)
218 const molecule * const _molecule = getMolecule(getMolIndex());
219 if (_molecule != NULL) {
220 owner = static_cast<const Observable *>(_molecule);
221 owner->signOn(this, molecule::AtomInserted);
222 owner->signOn(this, molecule::AtomRemoved);
223 owner->signOn(this, molecule::AtomMoved);
224 owner->signOn(this, molecule::IndexChanged);
225 } else {
226 ELOG(1, "GLMoleculeObject_molecule() - added null object for not present mol id " << getMolIndex());
227 }
228
229}
230
231void GLMoleculeObject_molecule::addAtomBonds(
232 const bond::ptr &_bond,
233 const GLMoleculeObject_bond::SideOfBond _side
234 )
235{
236 bool bond_present = false;
237 const BondIds ids = getBondIds(_bond, _side);
238 // check whether bond is not present already
239 bond_present = BondsinSceneMap.count(ids);
240 if (!bond_present)
241 bondInserted(ids.first, ids.second, _side);
242 else {
243 BondsinSceneMap[ids]->resetPosition();
244 BondsinSceneMap[ids]->resetWidth();
245 }
246}
247
248void GLMoleculeObject_molecule::addAtomBonds(
249 const atomId_t _id)
250{
251 const atom * const Walker = const_cast<const World &>(World::getInstance()).
252 getAtom(AtomById(_id));
253 if (Walker != NULL) {
254 const bool atom_present = AtomsinSceneMap.count(_id);
255 const BondList &bondlist = Walker->getListOfBonds();
256 for (BondList::const_iterator bonditer = bondlist.begin();
257 (bonditer != bondlist.end()) && atom_present;
258 ++bonditer) {
259 const bond::ptr _bond = *bonditer;
260 // check if OtherAtom's sphere is already present
261 const atom *OtherAtom = _bond->GetOtherAtom(Walker);
262 const bool otheratom_present = AtomsinSceneMap.count(OtherAtom->getId());
263 if (otheratom_present && atom_present) {
264 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == Walker) ?
265 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
266 const GLMoleculeObject_bond::SideOfBond otherside = (_bond->leftatom == Walker) ?
267 GLMoleculeObject_bond::right : GLMoleculeObject_bond::left;
268 addAtomBonds(_bond, side);
269 addAtomBonds(_bond, otherside);
270 }
271 }
272 } else
273 ELOG(1, "GLMoleculeObject_atom disappeared while about to add bonds.");
274}
275
276QGeometryData GLMoleculeObject_molecule::updateTesselationHull() const
277{
278 QGeometryData geo;
279
280 const molecule * const molref = getMolecule(getMolIndex());
281 if (molref == NULL) {
282 ELOG(1, "Could not createMoleculeMesh, molecule with id " << getMolIndex() << " already gone.");
283 return geo;
284 }
285 double minradius = 2.; // TODO: set to maximum bond length value
286 LOG(3, "DEBUG: Molecule fits into sphere of radius " << minradius);
287 // check minimum bond radius in molecule
288 double minlength = std::numeric_limits<double>::max();
289 for (molecule::const_iterator iter = molref->begin();
290 iter != molref->end(); ++iter) {
291 const BondList &ListOfBonds = (*iter)->getListOfBonds();
292 for (BondList::const_iterator bonditer = ListOfBonds.begin();
293 bonditer != ListOfBonds.end(); ++bonditer) {
294 const double bond_distance = (*bonditer)->GetDistance();
295 minlength = std::min(bond_distance, minlength);
296 }
297 }
298 minradius = std::max( std::max(minradius, minlength), 1.);
299
300 // we need at least three points for tesselation
301 if (getPresentAtoms().size() >= 3) {
302 // Tesselate the points.
303 Tesselation T;
304 PointCloudAdaptor<molecule> cloud(const_cast<molecule *>(molref), getMolName());
305 T(cloud, minradius);
306
307 // Fill the points into a Qt geometry.
308 LinkedCell_deprecated LinkedList(cloud, minradius);
309 std::map<int, int> indices;
310 std::map<int, Vector> normals;
311 int index = 0;
312 for (PointMap::const_iterator piter = T.PointsOnBoundary.begin();
313 piter != T.PointsOnBoundary.end(); ++piter) {
314 const Vector &point = piter->second->getPosition();
315 // add data to the primitive
316 geo.appendVertex(QVector3D(point[0], point[1], point[2]));
317 Vector normalvector;
318 for (LineMap::const_iterator lineiter = piter->second->lines.begin();
319 lineiter != piter->second->lines.end(); ++lineiter)
320 for (TriangleMap::const_iterator triangleiter = lineiter->second->triangles.begin();
321 triangleiter != lineiter->second->triangles.end(); ++triangleiter)
322 normalvector +=
323 triangleiter->second->NormalVector;
324 normalvector.Normalize();
325 geo.appendNormal(QVector3D(normalvector[0], normalvector[1], normalvector[2]));
326 geo.appendColor(QColor(1, 1, 1, 1));
327 geo.appendTexCoord(QVector2D(0, 0));
328 indices.insert( std::make_pair( piter->second->getNr(), index++));
329 }
330
331 // Fill the tesselated triangles into the geometry.
332 for (TriangleMap::const_iterator runner = T.TrianglesOnBoundary.begin();
333 runner != T.TrianglesOnBoundary.end(); runner++) {
334 int v[3];
335 for (size_t i=0; i<3; ++i)
336 v[i] = runner->second->endpoints[i]->getNr();
337
338 // Sort the vertices so the triangle is clockwise (relative to the normal vector).
339 Vector cross = T.PointsOnBoundary[v[1]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition();
340 cross.VectorProduct(T.PointsOnBoundary[v[2]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition());
341 if (cross.ScalarProduct(runner->second->NormalVector) > 0)
342 geo.appendIndices(indices[v[0]], indices[v[1]], indices[v[2]]);
343 else
344 geo.appendIndices(indices[v[0]], indices[v[2]], indices[v[1]]);
345 }
346 }
347
348 return geo;
349}
350
351molecule::BoundingBoxInfo GLMoleculeObject_molecule::initBoundingBox()
352{
353 molecule::BoundingBoxInfo info;
354 info.position = zeroVec;
355 info.radius = 0.;
356 return info;
357}
358
359molecule::BoundingBoxInfo GLMoleculeObject_molecule::updateBoundingBox(
360 const boost::function<const moleculeId_t ()> &_getMolIndex)
361{
362 const molecule * const mol = getMolecule(_getMolIndex());
363 return mol->getBoundingBox();
364}
365
366moleculeId_t GLMoleculeObject_molecule::updateIndex()
367{
368 return const_cast<const World &>(World::getInstance()).lastChangedMolId();
369}
370
371std::string GLMoleculeObject_molecule::updateName(
372 const boost::function<const moleculeId_t ()> &_getMolIndex)
373{
374 const molecule * const mol = getMolecule(_getMolIndex());
375 return mol->getName();
376}
377
378void GLMoleculeObject_molecule::resetTesselationHull()
379{
380 if (!TesselationHull.isValid())
381 updateMesh(createMoleculeMesh(*TesselationHull));
382}
383
384void GLMoleculeObject_molecule::resetBoundingBox()
385{
386 molecule::BoundingBoxInfo info = getBoundingBox();
387 setPosition(QVector3D(info.position[0], info.position[1], info.position[2]));
388 setScale(info.radius + 0.3); // getBoundingSphere() only sees atoms as points, so make the box a bit bigger
389}
390
391void GLMoleculeObject_molecule::resetAtoms()
392{
393 const atoms_t atoms = getPresentAtoms();
394 std::vector<atomId_t> InsertedAtoms;
395 std::vector<atomId_t> RemovedAtoms;
396 // obtain all newly inserted and removed atoms
397 std::set_difference(
398 atoms.begin(), atoms.end(),
399 DisplayedAtoms.begin(), DisplayedAtoms.end(),
400 std::back_inserter(InsertedAtoms));
401 std::set_difference(
402 DisplayedAtoms.begin(), DisplayedAtoms.end(),
403 atoms.begin(), atoms.end(),
404 std::back_inserter(RemovedAtoms));
405 // remove the atoms
406 std::for_each(RemovedAtoms.begin(), RemovedAtoms.end(),
407 boost::bind(&GLMoleculeObject_molecule::atomRemoved, this, _1));
408 // insert the atoms
409 std::for_each(InsertedAtoms.begin(), InsertedAtoms.end(),
410 boost::bind(&GLMoleculeObject_molecule::atomInserted, this, _1));
411 DisplayedAtoms = atoms;
412
413 emit changed();
414}
415
416void GLMoleculeObject_molecule::resetIndex()
417{
418 const atomId_t newId = getMolIndex();
419 const size_t oldId = objectId();
420 ASSERT( newId != oldId,
421 "GLMoleculeObject_molecule::resetIndex() - index "+toString(newId)+" did not change.");
422 LOG(4, "INFO: GLMoleculeObject_molecule: new index is "+toString(newId)+".");
423 setObjectId(newId);
424
425 emit indexChanged(this, oldId, newId);
426}
427
428void GLMoleculeObject_molecule::resetName()
429{
430}
431
432void GLMoleculeObject_molecule::AtomSelected(const atomId_t _id)
433{
434 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
435 if (iter != AtomsinSceneMap.end())
436 QMetaObject::invokeMethod(iter->second, // pointer to a QObject
437 "Selected", // member name (no parameters here)
438 Qt::QueuedConnection); // connection type
439 else
440 ELOG(2, "GLMoleculeObject_molecule::AtomSelected() - atom "
441 << _id << " unknown to GLMoleculeObject_molecule.");
442}
443
444void GLMoleculeObject_molecule::AtomUnselected(const atomId_t _id)
445{
446 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
447 if (iter != AtomsinSceneMap.end())
448 QMetaObject::invokeMethod(iter->second, // pointer to a QObject
449 "Unselected", // member name (no parameters here)
450 Qt::QueuedConnection); // connection type
451 else ELOG(2, "GLMoleculeObject_molecule::AtomUnselected() - atom "
452 << _id << " unknown to GLMoleculeObject_molecule.");
453}
454
455void GLMoleculeObject_molecule::Selected()
456{
457 ASSERT( !m_selected,
458 "GLMoleculeObject_molecule::Selected() - 3D rep of molecule is already selected.");
459 m_selected = true;
460
461 emit changed();
462}
463
464void GLMoleculeObject_molecule::Unselected()
465{
466 ASSERT( m_selected,
467 "GLMoleculeObject_molecule::Unselected() - 3D rep of molecule is already unselected.");
468 m_selected = false;
469
470 emit changed();
471}
472
473void GLMoleculeObject_molecule::update(Observable *publisher)
474{
475 ASSERT(0,
476 "GLMoleculeObject_molecule::update() - general update from unexpected source.");
477}
478
479void GLMoleculeObject_molecule::subjectKilled(Observable *publisher)
480{
481 // remove owner: no more signOff needed
482 owner = NULL;
483
484 countsubjectKilled(getMolIndex());
485}
486
487void GLMoleculeObject_molecule::recieveNotification(Observable *publisher, Notification_ptr notification)
488{
489 const molecule * const _molecule = getMolecule(getMolIndex());
490 // when molecule is NULL we will soon get destroyed anyway
491 if (_molecule == NULL)
492 return;
493 if (publisher == dynamic_cast<const Observable*>(_molecule)){
494 // notofication from atom
495#ifdef LOG_OBSERVER
496 observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
497 << " received notification from molecule " << getMolIndex() << " for channel "
498 << notification->getChannelNo() << ".";
499#endif
500 switch (notification->getChannelNo()) {
501 case molecule::AtomInserted:
502 {
503 const atomId_t _id = _molecule->lastChangedAtomId();
504 #ifdef LOG_OBSERVER
505 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
506 #endif
507 emit AtomInserted(_id);
508 emit TesselationHullChanged();
509 emit BoundingBoxChanged();
510 break;
511 }
512 case World::AtomRemoved:
513 {
514// const atomId_t _id = _molecule->lastChangedAtomId();
515 #ifdef LOG_OBSERVER
516 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed.";
517 #endif
518 emit TesselationHullChanged();
519 emit BoundingBoxChanged();
520 break;
521 }
522 case molecule::AtomMoved:
523 {
524 #ifdef LOG_OBSERVER
525 const atomId_t _id = _molecule->lastChangedAtomId();
526 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
527 #endif
528 emit TesselationHullChanged();
529 emit BoundingBoxChanged();
530 break;
531 }
532 case molecule::IndexChanged:
533 {
534 #ifdef LOG_OBSERVER
535 const atomId_t _id = _molecule->lastChangedAtomId();
536 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+"'s index has changed.";
537 #endif
538 emit IdChanged();
539 break;
540 }
541 default:
542 break;
543 }
544 }
545}
546
547void GLMoleculeObject_molecule::initialize(QGLView *view, QGLPainter *painter)
548{
549 // Initialize all of the mesh objects that we have as children.
550 if (m_visible) {
551 GLMoleculeObject::initialize(view, painter);
552 } else {
553 foreach (QObject *obj, children()) {
554 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
555 if (meshobj)
556 meshobj->initialize(view, painter);
557 }
558 }
559}
560
561void GLMoleculeObject_molecule::draw(QGLPainter *painter, const QVector4D &cameraPlane)
562{
563 // draw either molecule's mesh or all atoms and bonds
564 if (m_visible) {
565 resetTesselationHull();
566
567 painter->modelViewMatrix().push();
568
569 // Apply the material and effect to the painter.
570 QGLMaterial *material;
571 if (m_hovering)
572 material = m_hoverMaterial;
573 else if (m_selected)
574 material = m_selectionMaterial;
575 else
576 material = m_material;
577
578 ASSERT(material, "GLMoleculeObject::draw: chosen material is NULL");
579
580 painter->setColor(material->diffuseColor());
581 painter->setFaceMaterial(QGL::AllFaces, material);
582 if (m_effect)
583 painter->setUserEffect(m_effect);
584 else
585 painter->setStandardEffect(QGL::LitMaterial);
586
587 // Mark the object for object picking purposes.
588 int prevObjectId = painter->objectPickId();
589 if (m_objectId != -1)
590 painter->setObjectPickId(m_objectId);
591
592 m_mesh[0]->draw(painter);
593
594 // Turn off the user effect, if present.
595 if (m_effect)
596 painter->setStandardEffect(QGL::LitMaterial);
597
598 // Revert to the previous object identifier.
599 painter->setObjectPickId(prevObjectId);
600
601 // Restore the modelview matrix.
602 painter->modelViewMatrix().pop();
603
604 // GLMoleculeObject::draw(painter, cameraPlane);
605 } else {
606 // Draw all of the mesh objects that we have as children.
607 foreach (QObject *obj, children()) {
608 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
609 if (meshobj)
610 meshobj->draw(painter, cameraPlane);
611 }
612
613 // update bounding box prior to selection
614 resetBoundingBox();
615
616 painter->modelViewMatrix().push();
617 painter->modelViewMatrix().translate(m_position);
618 if (m_rotationAngle != 0.0f)
619 painter->modelViewMatrix().rotate(m_rotationAngle, m_rotationVector);
620 if ((m_scaleX != 1.0f) || (m_scaleY != 1.0f) || (m_scaleZ != 1.0f))
621 painter->modelViewMatrix().scale(m_scaleX, m_scaleY, m_scaleZ);
622
623 // Draw a box around the mesh, if selected.
624 if (m_selected)
625 drawSelectionBox(painter);
626
627 // Restore the modelview matrix.
628 painter->modelViewMatrix().pop();
629 }
630}
631
632/** Adds an atom of this molecule to the scene.
633 *
634 * @param _atom atom to add
635 */
636void GLMoleculeObject_molecule::atomInserted(const atomId_t _id)
637{
638 LOG(3, "INFO: GLMoleculeObject_molecule: Received signal atomInserted for atom "+toString(_id)+".");
639
640 GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(GLMoleculeObject::meshSphere, this, _id);
641 ASSERT( atomObject != NULL,
642 "GLMoleculeObject_molecule::atomInserted - could not create atom object for "+toString(_id));
643 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
644 ASSERT(iter == AtomsinSceneMap.end(),
645 "GLMoleculeObject_molecule::atomInserted - same atom with id "+toString(_id)+" added again.");
646 AtomsinSceneMap.insert( make_pair(_id, atomObject) );
647
648 qRegisterMetaType<atomId_t>("atomId_t");
649 qRegisterMetaType<bond::ptr>("bond::ptr");
650 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
651 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SIGNAL(atomClicked(atomId_t)));
652 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
653 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
654 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
655// connect (atomObject, SIGNAL(bondsChanged()), this, SLOT(bondInserted(const atomId_t, const atomId_t, const GLMoleculeObject_bond::SideOfBond)));
656 connect (atomObject, SIGNAL(BondsAdded(const atomId_t, const atomId_t, const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const atomId_t, const atomId_t, const GLMoleculeObject_bond::SideOfBond)));
657 connect (atomObject, SIGNAL(BondsRemoved(const atomId_t, const atomId_t)), this, SLOT(bondRemoved(const atomId_t, const atomId_t)));
658 connect (atomObject, SIGNAL(indexChanged(GLMoleculeObject_atom*, const atomId_t, const atomId_t)), this, SLOT(changeAtomId(GLMoleculeObject_atom*, const atomId_t, const atomId_t)));
659 connect (atomObject, SIGNAL(InstanceRemoved(const atomId_t)), this, SIGNAL(AtomRemoved(const atomId_t)));
660
661 if (m_objectId == -1)
662 setObjectId(_id);
663
664 // add all bonds
665 addAtomBonds(_id);
666
667 emit changeOccured();
668}
669
670/** Removes an atom of this molecule from the scene.
671 *
672 * We just the id as the atom might have already been destroyed.
673 *
674 * @param _id id of atom to remove
675 */
676void GLMoleculeObject_molecule::atomRemoved(const atomId_t _id)
677{
678 LOG(3, "INFO: GLMoleculeObject_molecule: Received signal atomRemoved for atom "+toString(_id)+".");
679 // bonds are removed by signal coming from ~bond
680
681 if ((unsigned int)m_objectId == _id)
682 setObjectId(-1);
683
684 // remove atoms
685 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
686 ASSERT(iter != AtomsinSceneMap.end(),
687 "GLMoleculeObject_molecule::atomRemoved() - atom "+toString(_id)+" not on display.");
688 GLMoleculeObject_atom *atomObject = iter->second;
689 AtomsinSceneMap.erase(iter);
690 atomObject->disconnect();
691 delete atomObject;
692
693 emit changeOccured();
694}
695
696void GLMoleculeObject_molecule::hoverChangedSignalled(GLMoleculeObject *ob)
697{
698 // Find the atom, ob corresponds to.
699 hoverAtomId = -1;
700 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
701 if (atomObject){
702 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
703 if (iter->second == atomObject)
704 hoverAtomId = iter->first;
705 }
706
707 // Propagate signal.
708 emit hoverChanged(hoverAtomId);
709 } else {
710 // Find the atom, ob corresponds to.
711 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
712 if (moleculeObject == this){
713 // Propagate signal.
714 emit hoverChanged(getMolIndex(), 0);
715 }
716 }
717}
718
719
720/** Helper function to get bond ids in the correct order for BondNodeMap.
721 *
722 * \return pair of ids in correct order.
723 */
724GLMoleculeObject_molecule::BondIds GLMoleculeObject_molecule::getBondIds(
725 const bond::ptr _bond,
726 const enum GLMoleculeObject_bond::SideOfBond _side)
727{
728 BondIds ids;
729 switch (_side) {
730 case GLMoleculeObject_bond::left:
731 ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId());
732 break;
733 case GLMoleculeObject_bond::right:
734 ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId());
735 break;
736 }
737 return ids;
738}
739
740/** Adds a bond to the scene.
741 *
742 * @param _bond bond to add
743 * @param side which side of the bond (left or right)
744 */
745void GLMoleculeObject_molecule::bondInserted(
746 const atomId_t _left, const atomId_t _right,
747 const enum GLMoleculeObject_bond::SideOfBond _side)
748{
749 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(_left)
750 +toString(_right)+".");
751 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");
752
753 const BondIds ids( std::make_pair(_left, _right) );
754 BondNodeMap::iterator iter = BondsinSceneMap.find(ids);
755 if (iter == BondsinSceneMap.end()) {
756 GLMoleculeObject_bond * bondObject =
757 new GLMoleculeObject_bond(GLMoleculeObject::meshCylinder, this, ids, _side);
758 connect (
759 bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)),
760 this, SLOT(bondRemoved(const atomId_t, const atomId_t)));
761 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
762 BondsinSceneMap.insert( make_pair(ids, bondObject) );
763 // BondIdsinSceneMap.insert( Leftids );
764 } else {
765 iter->second->resetPosition();
766 iter->second->resetWidth();
767 }
768 emit changeOccured();
769}
770
771/** Removes a bond from the scene.
772 *
773 * @param _bond bond to remove
774 */
775void GLMoleculeObject_molecule::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
776{
777 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");
778 {
779 // left bond
780 const BondIds Leftids( make_pair(leftnr, rightnr) );
781 BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
782 ASSERT(leftiter != BondsinSceneMap.end(),
783 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
784 +toString(rightnr)+" not on display.");
785 GLMoleculeObject_bond *bondObject = leftiter->second;
786 bondObject->disconnect();
787 BondsinSceneMap.erase(leftiter);
788 delete bondObject; // is done by signal from bond itself
789 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");
790 }
791
792 emit changeOccured();
793}
794
795void GLMoleculeObject_molecule::setVisible(bool value)
796{
797 // first update the mesh if we are going to be visible now
798 if (value)
799 updateTesselationHull();
800 // then emit onward
801 GLMoleculeObject::setVisible(value);
802}
803
804std::ostream &operator<<(std::ostream &ost, const GLMoleculeObject_molecule::BondIds &t)
805{
806 ost << t.first << "," << t.second;
807 return ost;
808}
809
810void GLMoleculeObject_molecule::wasClicked()
811{
812 LOG(4, "INFO: GLMoleculeObject_molecule: atom " << getMolIndex() << " has been clicked");
813 emit moleculeClicked(getMolIndex());
814}
815
816void GLMoleculeObject_molecule::changeAtomId(
817 GLMoleculeObject_atom *ob,
818 const atomId_t oldId,
819 const atomId_t newId)
820{
821 LOG(3, "INFO: GLMoleculeObject_molecule - change atom id " << oldId << " to " << newId << ".");
822
823 // Remove from map.
824 AtomNodeMap::iterator iter = AtomsinSceneMap.find(oldId);
825 ASSERT(iter != AtomsinSceneMap.end(),
826 "GLMoleculeObject_molecule::changeAtomId() - atom with old id "+toString(oldId)+" not on display.");
827 ASSERT(iter->second == ob,
828 "GLMoleculeObject_molecule::changeAtomId() - atom with id "
829 +toString(oldId)+" does not match with object in AtomsinSceneMap.");
830 AtomsinSceneMap.erase(iter);
831
832 // Reinsert with new id.
833 {
834 AtomNodeMap::iterator iter = AtomsinSceneMap.find(newId);
835 ASSERT(iter == AtomsinSceneMap.end(),
836 "GLMoleculeObject_molecule::changeAtomId() - atom with new id "+toString(newId)+" already known.");
837 }
838 AtomsinSceneMap.insert( make_pair(newId, ob) );
839}
840
841const molecule * const GLMoleculeObject_molecule::getMolecule(const moleculeId_t _id)
842{
843 const molecule * const mol = const_cast<const World &>(World::getInstance()).
844 getMolecule(MoleculeById(_id));
845 return mol;
846}
847
848void GLMoleculeObject_molecule::countsubjectKilled(const moleculeId_t)
849{
850 ++subjectKilledCount;
851
852 if (subjectKilledCount > ObservedValues.size())
853 emit InstanceRemoved(getMolIndex());
854}
855
856void GLMoleculeObject_molecule::initObservedValues(
857 std::vector<boost::any> &_ObservedValues,
858 const moleculeId_t _molid,
859 const molecule * const _molref,
860 const boost::function<void(const moleculeId_t)> &_subjectKilled)
861{
862 /* This is an old note from when the code was still part of cstor's initializer body.
863 * TODO: Probably does not apply anymore but has not yet been tested.
864 *
865 * We must not use boost::cref(this) as "this" has not been properly constructed and seemingly
866 * boost::cref tries to do some magic to grasp the inheritance hierarchy which fails because
867 * the class has not been fully constructed yet. "This" itself seems to be working fine.
868 */
869
870 ASSERT( _ObservedValues.size() == MAX_ObservedTypes,
871 "GLMoleculeObject_molecule::initObservedValues() - given ObservedValues has not correct size.");
872
873 // fill ObservedValues: index first
874 const boost::function<moleculeId_t ()> MolIndexUpdater(
875 boost::bind(&GLMoleculeObject_molecule::updateIndex));
876
877 ObservedValue_wCallback<moleculeId_t> * const IndexObservable =
878 new ObservedValue_wCallback<moleculeId_t>(
879 _molref,
880 MolIndexUpdater,
881 "MoleculeIndex_"+toString(_molid),
882 _molid,
883 IndexChannels,
884 _subjectKilled);
885 _ObservedValues[MolIndex] = IndexObservable;
886
887 const boost::function<const moleculeId_t ()> MolIndexGetter =
888 boost::bind(&ObservedValue_wCallback<moleculeId_t>::get,
889 IndexObservable);
890
891 // fill ObservedValues: then all the other that need index
892 const boost::function<std::string ()> MolNameUpdater(
893 boost::bind(&GLMoleculeObject_molecule::updateName, MolIndexGetter));
894 const boost::function<molecule::BoundingBoxInfo ()> BoundingBoxUpdater(
895 boost::bind(&GLMoleculeObject_molecule::updateBoundingBox, MolIndexGetter));
896
897 _ObservedValues[MolName] = new ObservedValue_wCallback<std::string, moleculeId_t>(
898 _molref,
899 MolNameUpdater,
900 "MoleculeName_"+toString(_molid),
901 MolNameUpdater(),
902 NameChannels,
903 _subjectKilled,
904 MolIndexGetter);
905 _ObservedValues[BoundingBox] = new ObservedValue_wCallback<molecule::BoundingBoxInfo, moleculeId_t>(
906 _molref,
907 BoundingBoxUpdater,
908 "MoleculeBoundingBox_"+toString(_molid),
909 initBoundingBox(),
910 BoundingBoxChannels,
911 _subjectKilled,
912 MolIndexGetter);
913 _ObservedValues[PresentAtoms] = new ObservedValue_UpdateAtoms(
914 _molref,
915 "MoleculeAtoms_"+toString(_molid),
916 AtomsChannels,
917 _subjectKilled,
918 MolIndexGetter);
919}
920
921void GLMoleculeObject_molecule::destroyObservedValues(
922 std::vector<boost::any> &_ObservedValues)
923{
924 delete boost::any_cast<ObservedValue_wCallback<moleculeId_t> *>(_ObservedValues[MolIndex]);
925 delete boost::any_cast<ObservedValue_wCallback<std::string, moleculeId_t> *>(_ObservedValues[MolName]);
926 delete boost::any_cast<ObservedValue_wCallback<molecule::BoundingBoxInfo, moleculeId_t> *>(_ObservedValues[BoundingBox]);
927 delete boost::any_cast<ObservedValue_UpdateAtoms *>(_ObservedValues[PresentAtoms]);
928 _ObservedValues.clear();
929}
930
931moleculeId_t GLMoleculeObject_molecule::getMolIndex() const
932{
933 return boost::any_cast<ObservedValue_wCallback<moleculeId_t> *>(ObservedValues[MolIndex])->get();
934}
935
936std::string GLMoleculeObject_molecule::getMolName() const
937{
938 return boost::any_cast<ObservedValue_wCallback<std::string, moleculeId_t> *>(ObservedValues[MolName])->get();
939}
940
941molecule::BoundingBoxInfo GLMoleculeObject_molecule::getBoundingBox() const
942{
943 return boost::any_cast<ObservedValue_wCallback<molecule::BoundingBoxInfo, moleculeId_t> *>(ObservedValues[BoundingBox])->get();
944}
945
946GLMoleculeObject_molecule::atoms_t GLMoleculeObject_molecule::getPresentAtoms() const
947{
948 return boost::any_cast<ObservedValue_UpdateAtoms *>(ObservedValues[PresentAtoms])->get();
949}
Note: See TracBrowser for help on using the repository browser.