source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp@ 7a205a

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

FIX: GLMoleculeObject_molecule::updateAtoms() used DisplayAtoms directly.

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