source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp@ 07b800

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 07b800 was a39d72, checked in by Frederik Heber <heber@…>, 10 years ago

Fixed formula usage in Qt part of code.

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