source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.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 8688ef, checked in by Frederik Heber <heber@…>, 9 years ago

GLMoleculeObject_molecule's ObservedValues is now all static.

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