source: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp@ 057c8a

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 057c8a was 6fe4f7, checked in by Frederik Heber <heber@…>, 10 years ago

FIX: updateBoundingBox() must not call molecule::getBoundingBox() on every update.

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