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

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

FIX: GLMoleculeObject_molecule() may overlap with atomInserted() signal.

  • this is because GLMoleculeObject_molecule takes some time till init() is called and its runs in a separate thread (hence, further atoms may be loaded into the just created atoms). As we first signOn() and then call init(), we may end up initializing atoms whose atomInserted signal then also comes in but lateron. This causes the AtomsInSceneMap to have double entries and the assertion to fail. We now keep book of all atomic ids inserted during init() and these are ok to appear doubly and their signal is skipped.
  • Property mode set to 100644
File size: 26.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
33
34
35// include config.h
36#ifdef HAVE_CONFIG_H
37#include <config.h>
38#endif
39
40#include "GLMoleculeObject_molecule.hpp"
41
42#include <Qt3D/qglscenenode.h>
43#include <Qt3D/qglbuilder.h>
44
45#include "CodePatterns/MemDebug.hpp"
46
47#include "CodePatterns/Assert.hpp"
48#include "CodePatterns/Log.hpp"
49#include "CodePatterns/Observer/Notification.hpp"
50#include "CodePatterns/Observer/ObserverLog.hpp"
51
52#include "Atom/atom.hpp"
53#include "molecule.hpp"
54#include "Descriptors/AtomIdDescriptor.hpp"
55#include "Descriptors/MoleculeIdDescriptor.hpp"
56#include "Element/element.hpp"
57#include "LinearAlgebra/Vector.hpp"
58#include "LinkedCell/PointCloudAdaptor.hpp"
59#include "LinkedCell/linkedcell.hpp"
60#include "Tesselation/tesselation.hpp"
61#include "Tesselation/BoundaryLineSet.hpp"
62#include "Tesselation/BoundaryTriangleSet.hpp"
63#include "Tesselation/CandidateForTesselation.hpp"
64#include "Atom/TesselPoint.hpp"
65#include "World.hpp"
66
67#include "GLMoleculeObject_atom.hpp"
68
69static QGLSceneNode *createMoleculeMesh(const moleculeId_t molid, QObject *parent)
70{
71 const molecule *molref = const_cast<const World &>(World::getInstance()).
72 getMolecule(MoleculeById(molid));
73 if (molref == NULL) {
74 ELOG(1, "Could not createMoleculeMesh, molecule with id " << molid << " already gone.");
75 return NULL;
76 }
77// Shape shape = molref->getBoundingSphere();
78 double minradius = 2.; // TODO: set to maximum bond length value
79 LOG(3, "DEBUG: Molecule fits into sphere of radius " << minradius);
80 // check minimum bond radius in molecule
81 double minlength = std::numeric_limits<double>::max();
82 for (molecule::const_iterator iter = molref->begin();
83 iter != molref->end(); ++iter) {
84 const BondList &ListOfBonds = (*iter)->getListOfBonds();
85 for (BondList::const_iterator bonditer = ListOfBonds.begin();
86 bonditer != ListOfBonds.end(); ++bonditer) {
87 const double bond_distance = (*bonditer)->GetDistance();
88 minlength = std::min(bond_distance, minlength);
89 }
90 }
91 minradius = std::max( std::max(minradius, minlength), 1.);
92
93 QGeometryData geo;
94 // we need at least three points for tesselation
95 if (molref->getAtomCount() >= 3) {
96 // Tesselate the points.
97 Tesselation T;
98 PointCloudAdaptor<molecule> cloud(const_cast<molecule *>(molref), molref->getName());
99 T(cloud, minradius);
100
101 // Fill the points into a Qt geometry.
102 LinkedCell_deprecated LinkedList(cloud, minradius);
103 std::map<int, int> indices;
104 std::map<int, Vector> normals;
105 int index = 0;
106 for (PointMap::const_iterator piter = T.PointsOnBoundary.begin();
107 piter != T.PointsOnBoundary.end(); ++piter) {
108 const Vector &point = piter->second->getPosition();
109 // add data to the primitive
110 geo.appendVertex(QVector3D(point[0], point[1], point[2]));
111 Vector normalvector;
112 for (LineMap::const_iterator lineiter = piter->second->lines.begin();
113 lineiter != piter->second->lines.end(); ++lineiter)
114 for (TriangleMap::const_iterator triangleiter = lineiter->second->triangles.begin();
115 triangleiter != lineiter->second->triangles.end(); ++triangleiter)
116 normalvector +=
117 triangleiter->second->NormalVector;
118 normalvector.Normalize();
119 geo.appendNormal(QVector3D(normalvector[0], normalvector[1], normalvector[2]));
120 geo.appendColor(QColor(1, 1, 1, 1));
121 geo.appendTexCoord(QVector2D(0, 0));
122 indices.insert( std::make_pair( piter->second->getNr(), index++));
123 }
124
125 // Fill the tesselated triangles into the geometry.
126 for (TriangleMap::const_iterator runner = T.TrianglesOnBoundary.begin();
127 runner != T.TrianglesOnBoundary.end(); runner++) {
128 int v[3];
129 for (size_t i=0; i<3; ++i)
130 v[i] = runner->second->endpoints[i]->getNr();
131
132 // Sort the vertices so the triangle is clockwise (relative to the normal vector).
133 Vector cross = T.PointsOnBoundary[v[1]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition();
134 cross.VectorProduct(T.PointsOnBoundary[v[2]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition());
135 if (cross.ScalarProduct(runner->second->NormalVector) > 0)
136 geo.appendIndices(indices[v[0]], indices[v[1]], indices[v[2]]);
137 else
138 geo.appendIndices(indices[v[0]], indices[v[2]], indices[v[1]]);
139 }
140 }
141
142 // Build a mesh from the geometry.
143 QGLBuilder builder;
144 builder.addTriangles(geo);
145 QGLSceneNode *mesh = builder.finalizedSceneNode();
146 return mesh;
147}
148
149GLMoleculeObject_molecule::GLMoleculeObject_molecule(QObject *parent, const moleculeId_t molid) :
150 GLMoleculeObject(createMoleculeMesh(molid, parent), parent),
151 Observer(std::string("GLMoleculeObject_molecule")+toString(molid)),
152 isBoundingBoxUptodate(true),
153 isSignedOn(false),
154 moleculeid(molid),
155 TesselationHullUptodate(true),
156 hoverAtomId(-1)
157{
158 // sign on as observer (obtain non-const instance before)
159 const molecule *_molecule = const_cast<const World &>(World::getInstance()).
160 getMolecule(MoleculeById(moleculeid));
161 if (_molecule != NULL) {
162 _molecule->signOn(this, molecule::AtomInserted);
163 _molecule->signOn(this, molecule::AtomRemoved);
164 _molecule->signOn(this, molecule::AtomMoved);
165 isSignedOn = true;
166 } else {
167 ELOG(1, "GLMoleculeObject_molecule() - added null object for not present mol id " << moleculeid);
168 }
169 /*molref->signOn(this, AtomObservable::IndexChanged);
170 molref->signOn(this, AtomObservable::PositionChanged);
171 molref->signOn(this, AtomObservable::ElementChanged);
172 molref->signOn(this, AtomObservable::BondsAdded);*/
173 setMaterial(getMaterial(1));
174 World::getInstance().signOn(this, World::SelectionChanged);
175 updateBoundingBox();
176
177 // initially, atoms and bonds should be visible
178 m_visible = false;
179
180 init();
181
182 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
183 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
184
185 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
186}
187
188GLMoleculeObject_molecule::GLMoleculeObject_molecule(QGLSceneNode *mesh[], QObject *parent, const moleculeId_t molid) :
189 GLMoleculeObject(mesh, parent),
190 Observer(std::string("GLMoleculeObject_molecule")+toString(molid)),
191 isBoundingBoxUptodate(true),
192 isSignedOn(false),
193 moleculeid(molid),
194 TesselationHullUptodate(true),
195 hoverAtomId(-1)
196{
197 // sign on as observer (obtain non-const instance before)
198 const molecule *_molecule = const_cast<const World &>(World::getInstance()).
199 getMolecule(MoleculeById(moleculeid));
200 if (_molecule != NULL) {
201 _molecule->signOn(this, molecule::AtomInserted);
202 _molecule->signOn(this, molecule::AtomRemoved);
203 _molecule->signOn(this, molecule::AtomMoved);
204 isSignedOn = true;
205 } else {
206 ELOG(1, "GLMoleculeObject_molecule() - added null object for not present mol id " << moleculeid);
207 }
208 /*molref->signOn(this, AtomObservable::IndexChanged);
209 molref->signOn(this, AtomObservable::PositionChanged);
210 molref->signOn(this, AtomObservable::ElementChanged);
211 molref->signOn(this, AtomObservable::BondsAdded);*/
212 setMaterial(getMaterial(1));
213 World::getInstance().signOn(this, World::SelectionChanged);
214 updateBoundingBox();
215
216 // initially, atoms and bonds should be visible
217 m_visible = false;
218
219 init();
220
221 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
222 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
223
224 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
225}
226
227GLMoleculeObject_molecule::~GLMoleculeObject_molecule()
228{
229 if (isSignedOn) {
230 const molecule *_molecule = const_cast<const World &>(World::getInstance()).
231 getMolecule(MoleculeById(moleculeid));
232 if (_molecule != NULL) {
233 _molecule->signOff(this, molecule::AtomInserted);
234 _molecule->signOff(this, molecule::AtomRemoved);
235 _molecule->signOff(this, molecule::AtomMoved);
236 } else {
237 ELOG(1, "GLMoleculeObject_molecule cannot sign off, molecule with "
238 << moleculeid << " has disappeared.");
239 }
240 }
241 /*_atom->signOff(this, AtomObservable::IndexChanged);
242 _atom->signOff(this, AtomObservable::PositionChanged);
243 _atom->signOff(this, AtomObservable::ElementChanged);
244 _atom->signOff(this, AtomObservable::BondsAdded);*/
245 World::getInstance().signOff(this, World::SelectionChanged);
246}
247
248/** Initialise the WorldScene with molecules and atoms from World.
249 *
250 */
251void GLMoleculeObject_molecule::init()
252{
253 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
254 getMolecule(MoleculeById(moleculeid));
255 if (_molecule == NULL) {
256 ELOG(1, "GLMoleculeObject_molecule cannot init, molecule with "
257 << moleculeid << " has disappeared.");
258 return;
259 }
260 if (_molecule->begin() != _molecule->end()) {
261 int atomicid = -1;
262 for (molecule::const_iterator atomiter = _molecule->begin();
263 atomiter != _molecule->end();
264 atomiter++) {
265 // create atom objects in scene
266 atomicid = (*atomiter)->getId();
267 atomInserted(atomicid);
268 InitAtomNodesSet.insert(atomicid);
269
270 // create bond objects in scene
271 const BondList &bondlist = (*atomiter)->getListOfBonds();
272 for (BondList::const_iterator bonditer = bondlist.begin();
273 bonditer != bondlist.end();
274 ++bonditer) {
275 const bond::ptr _bond = *bonditer;
276 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == *atomiter) ?
277 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
278 bondInserted(_bond, side);
279 }
280 }
281 // set id to one of the atom's as either mol or atoms is present at the same time
282 setObjectId(atomicid);
283 }
284}
285
286void GLMoleculeObject_molecule::addAtomBonds(
287 const bond::ptr &_bond,
288 const GLMoleculeObject_bond::SideOfBond _side
289 )
290{
291 bool bond_present = false;
292 const BondIds ids = getBondIds(_bond, _side);
293 // check whether bond is not present already
294 bond_present = BondsinSceneMap.count(ids);
295 if (!bond_present)
296 bondInserted(_bond, _side);
297 else {
298 BondsinSceneMap[ids]->resetPosition();
299 BondsinSceneMap[ids]->resetWidth();
300 }
301}
302
303void GLMoleculeObject_molecule::addAtomBonds(
304 const atom *_atom)
305{
306 const bool atom_present = AtomsinSceneMap.count(_atom->getId());
307 const BondList &bondlist = _atom->getListOfBonds();
308 for (BondList::const_iterator bonditer = bondlist.begin();
309 (bonditer != bondlist.end()) && atom_present;
310 ++bonditer) {
311 const bond::ptr _bond = *bonditer;
312 // check if OtherAtom's sphere is already present
313 const atom *OtherAtom = _bond->GetOtherAtom(_atom);
314 const bool otheratom_present = AtomsinSceneMap.count(OtherAtom->getId());
315 if (otheratom_present && atom_present) {
316 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ?
317 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
318 const GLMoleculeObject_bond::SideOfBond otherside = (_bond->leftatom == _atom) ?
319 GLMoleculeObject_bond::right : GLMoleculeObject_bond::left;
320 addAtomBonds(_bond, side);
321 addAtomBonds(_bond, otherside);
322 }
323 }
324}
325
326void GLMoleculeObject_molecule::reinit()
327{
328 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
329 getMolecule(MoleculeById(moleculeid));
330 if (_molecule == NULL) {
331 ELOG(1, "GLMoleculeObject_molecule cannot reinit, molecule with "
332 << moleculeid << " has disappeared.");
333 return;
334 }
335 if (_molecule->getAtomCount() > 0) {
336 for (molecule::const_iterator atomiter = _molecule->begin();
337 atomiter != _molecule->end();
338 atomiter++) {
339 // check whether atom already exists
340 const atomId_t atomid = (*atomiter)->getId();
341 const bool atom_present = AtomsinSceneMap.count(atomid);
342 if (!atom_present)
343 atomInserted((*atomiter)->getId());
344 else
345 AtomsinSceneMap[atomid]->resetPosition();
346
347
348 // create bond objects in scene
349 addAtomBonds(*atomiter);
350 }
351 }
352}
353
354void GLMoleculeObject_molecule::updateBoundingBox()
355{
356 isBoundingBoxUptodate = true;
357 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
358 getMolecule(MoleculeById(moleculeid));
359 if (_molecule == NULL) {
360 ELOG(1, "GLMoleculeObject_molecule cannot updateBoundingBox, molecule with "
361 << moleculeid << " has disappeared.");
362 return;
363 }
364 Shape shape = _molecule->getBoundingSphere();
365 Vector v = shape.getCenter();
366 setPosition(QVector3D(v[0], v[1], v[2]));
367 setScale(shape.getRadius() + 0.3); // getBoundingShape() only sees atoms as points, so make the box a bit bigger
368}
369
370void GLMoleculeObject_molecule::update(Observable *publisher)
371{
372#ifdef LOG_OBSERVER
373 const molecule *_mol = static_cast<molecule *>(publisher);
374 observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(static_cast<Observer *>(this)) << " from molecule "+toString(_mol->getId())+".";
375#endif
376}
377
378void GLMoleculeObject_molecule::subjectKilled(Observable *publisher)
379{
380 isSignedOn = false;
381}
382
383void GLMoleculeObject_molecule::recieveNotification(Observable *publisher, Notification_ptr notification)
384{
385 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
386 getMolecule(MoleculeById(moleculeid));
387 if (publisher == dynamic_cast<const Observable*>(_molecule)){
388 // notofication from atom
389#ifdef LOG_OBSERVER
390 observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
391 << " received notification from molecule " << _molecule->getId() << " for channel "
392 << notification->getChannelNo() << ".";
393#endif
394 switch (notification->getChannelNo()) {
395 case molecule::AtomInserted:
396 {
397 const atomId_t _id = _molecule->lastChanged()->getId();
398 #ifdef LOG_OBSERVER
399 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
400 #endif
401 TesselationHullUptodate = false;
402 isBoundingBoxUptodate = false;
403 atomInserted(_id);
404 break;
405 }
406 case World::AtomRemoved:
407 {
408 const atomId_t _id = _molecule->lastChanged()->getId();
409 #ifdef LOG_OBSERVER
410 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed.";
411 #endif
412 TesselationHullUptodate = false;
413 isBoundingBoxUptodate = false;
414 atomRemoved(_id);
415 break;
416 }
417 case molecule::AtomMoved:
418 {
419 #ifdef LOG_OBSERVER
420 const atomId_t _id = _molecule->lastChanged()->getId();
421 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
422 #endif
423 TesselationHullUptodate = false;
424 isBoundingBoxUptodate = false;
425 break;
426 }
427 default:
428 break;
429 }
430 }else{
431 // notification from world
432#ifdef LOG_OBSERVER
433 observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
434 << " received notification from world for channel "
435 << notification->getChannelNo() << ".";
436#endif
437 switch (notification->getChannelNo()) {
438 case World::SelectionChanged:
439 if (_molecule != NULL) {
440 setSelected(World::getInstance().isSelected(_molecule));
441 } else {
442 ELOG(1, "GLMoleculeObject_molecule cannot change selection, molecule with "
443 << moleculeid << " has disappeared.");
444 }
445 break;
446 default:
447 break;
448 }
449 }
450}
451
452void GLMoleculeObject_molecule::initialize(QGLView *view, QGLPainter *painter)
453{
454 // Initialize all of the mesh objects that we have as children.
455 if (m_visible) {
456 GLMoleculeObject::initialize(view, painter);
457 } else {
458 foreach (QObject *obj, children()) {
459 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
460 if (meshobj)
461 meshobj->initialize(view, painter);
462 }
463 }
464}
465
466void GLMoleculeObject_molecule::draw(QGLPainter *painter, const QVector4D &cameraPlane)
467{
468 // draw either molecule's mesh or all atoms and bonds
469 if (m_visible) {
470 updateTesselationHull();
471
472 painter->modelViewMatrix().push();
473
474 // Apply the material and effect to the painter.
475 QGLMaterial *material;
476 if (m_hovering)
477 material = m_hoverMaterial;
478 else if (m_selected)
479 material = m_selectionMaterial;
480 else
481 material = m_material;
482
483 ASSERT(material, "GLMoleculeObject::draw: chosen material is NULL");
484
485 painter->setColor(material->diffuseColor());
486 painter->setFaceMaterial(QGL::AllFaces, material);
487 if (m_effect)
488 painter->setUserEffect(m_effect);
489 else
490 painter->setStandardEffect(QGL::LitMaterial);
491
492 // Mark the object for object picking purposes.
493 int prevObjectId = painter->objectPickId();
494 if (m_objectId != -1)
495 painter->setObjectPickId(m_objectId);
496
497 m_mesh[0]->draw(painter);
498
499 // Turn off the user effect, if present.
500 if (m_effect)
501 painter->setStandardEffect(QGL::LitMaterial);
502
503 // Revert to the previous object identifier.
504 painter->setObjectPickId(prevObjectId);
505
506 // Restore the modelview matrix.
507 painter->modelViewMatrix().pop();
508
509 // GLMoleculeObject::draw(painter, cameraPlane);
510 } else {
511 // Draw all of the mesh objects that we have as children.
512 foreach (QObject *obj, children()) {
513 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
514 if (meshobj)
515 meshobj->draw(painter, cameraPlane);
516 }
517
518 // update bounding box prior to selection
519 if (!isBoundingBoxUptodate)
520 updateBoundingBox();
521
522 painter->modelViewMatrix().push();
523 painter->modelViewMatrix().translate(m_position);
524 if (m_rotationAngle != 0.0f)
525 painter->modelViewMatrix().rotate(m_rotationAngle, m_rotationVector);
526 if ((m_scaleX != 1.0f) || (m_scaleY != 1.0f) || (m_scaleZ != 1.0f))
527 painter->modelViewMatrix().scale(m_scaleX, m_scaleY, m_scaleZ);
528
529 // Draw a box around the mesh, if selected.
530 if (m_selected)
531 drawSelectionBox(painter);
532
533 // Restore the modelview matrix.
534 painter->modelViewMatrix().pop();
535 }
536}
537
538/** Adds an atom of this molecule to the scene.
539 *
540 * @param _atom atom to add
541 */
542void GLMoleculeObject_molecule::atomInserted(const atomicNumber_t _id)
543{
544 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "+toString(_id)+".");
545 // remove ids if second insertion via update comes in
546 if ((!InitAtomNodesSet.empty()) && (InitAtomNodesSet.find(_id) != InitAtomNodesSet.end())) {
547 // the problem is as follows:
548 // In order to get really all atoms, we first signOn to molecule and then call init()
549 // however, in init() further atoms may have been loaded which are then also
550 // instantiated by init(). Note only that but we also obtain an update() from
551 // molecule itself (because we signOn'd before) that a new atom is to be inserted
552 // hence, this would cause double insertion of the same atom and this has to be
553 // caught
554 InitAtomNodesSet.erase(_id);
555 LOG(4, "Atom with " << _id << " has already been added.");
556 } else {
557 GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(GLMoleculeObject::meshSphere, this, _id);
558 ASSERT( atomObject != NULL,
559 "GLMoleculeObject_molecule::atomInserted - could not create atom object for "+toString(_id));
560 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
561 ASSERT(iter == AtomsinSceneMap.end(),
562 "GLMoleculeObject_molecule::atomInserted - same atom with id "+toString(_id)+" added again.");
563 AtomsinSceneMap.insert( make_pair(_id, atomObject) );
564
565 qRegisterMetaType<atomId_t>("atomId_t");
566 qRegisterMetaType<bond::ptr>("bond::ptr");
567 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
568 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SIGNAL(atomClicked(atomId_t)));
569 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
570 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
571 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
572 connect (atomObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
573 connect (atomObject, SIGNAL(BondsInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)));
574 connect (atomObject, SIGNAL(indexChanged(GLMoleculeObject_atom*, int, int)), this, SIGNAL(changeAtomId(GLMoleculeObject_atom*, int, int)));
575
576 isBoundingBoxUptodate = false;
577
578 if (m_objectId == -1)
579 setObjectId(_id);
580 }
581
582 // add all bonds
583 const atom * const Walker = const_cast<const World &>(World::getInstance()).
584 getAtom(AtomById(_id));
585 if (Walker != NULL)
586 addAtomBonds(Walker);
587 else
588 ELOG(1, "GLMoleculeObject_atom disappeared while about to add bonds.");
589
590 emit changeOccured();
591}
592
593/** Removes an atom of this molecule from the scene.
594 *
595 * We just the id as the atom might have already been destroyed.
596 *
597 * @param _id id of atom to remove
598 */
599void GLMoleculeObject_molecule::atomRemoved(const atomicNumber_t _id)
600{
601 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_id)+".");
602 // bonds are removed by signal coming from ~bond
603
604 if ((unsigned int)m_objectId == _id)
605 setObjectId(-1);
606
607 // remove atoms
608 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
609 ASSERT(iter != AtomsinSceneMap.end(),
610 "GLWorldScene::atomRemoved() - atom "+toString(_id)+" not on display.");
611 GLMoleculeObject_atom *atomObject = iter->second;
612 AtomsinSceneMap.erase(iter);
613 atomObject->disconnect();
614 delete atomObject;
615
616 isBoundingBoxUptodate = false;
617
618 emit changeOccured();
619}
620
621void GLMoleculeObject_molecule::hoverChangedSignalled(GLMoleculeObject *ob)
622{
623 // Find the atom, ob corresponds to.
624 hoverAtomId = -1;
625 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
626 if (atomObject){
627 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
628 if (iter->second == atomObject)
629 hoverAtomId = iter->first;
630 }
631
632 // Propagate signal.
633 emit hoverChanged(hoverAtomId);
634 } else {
635 // Find the atom, ob corresponds to.
636 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
637 if (moleculeObject == this){
638 // Propagate signal.
639 emit hoverChanged(moleculeid, 0);
640 }
641 }
642}
643
644
645/** Helper function to get bond ids in the correct order for BondNodeMap.
646 *
647 * \return pair of ids in correct order.
648 */
649GLMoleculeObject_molecule::BondIds GLMoleculeObject_molecule::getBondIds(
650 const bond::ptr _bond,
651 const enum GLMoleculeObject_bond::SideOfBond _side)
652{
653 BondIds ids;
654 switch (_side) {
655 case GLMoleculeObject_bond::left:
656 ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId());
657 break;
658 case GLMoleculeObject_bond::right:
659 ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId());
660 break;
661 }
662 return ids;
663}
664
665/** Adds a bond to the scene.
666 *
667 * @param _bond bond to add
668 * @param side which side of the bond (left or right)
669 */
670void GLMoleculeObject_molecule::bondInserted(const bond::ptr _bond, const enum GLMoleculeObject_bond::SideOfBond _side)
671{
672 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");
673 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");
674
675 const BondIds ids = getBondIds(_bond, _side);
676 BondNodeMap::iterator iter = BondsinSceneMap.find(ids);
677 if (iter == BondsinSceneMap.end()) {
678 GLMoleculeObject_bond * bondObject =
679 new GLMoleculeObject_bond(GLMoleculeObject::meshCylinder, this, _bond, _side);
680 connect (
681 bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)),
682 this, SLOT(bondRemoved(const atomId_t, const atomId_t)));
683 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
684 BondsinSceneMap.insert( make_pair(ids, bondObject) );
685 // BondIdsinSceneMap.insert( Leftids );
686 } else {
687 iter->second->resetPosition();
688 iter->second->resetWidth();
689 }
690 emit changeOccured();
691}
692
693/** Removes a bond from the scene.
694 *
695 * @param _bond bond to remove
696 */
697void GLMoleculeObject_molecule::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
698{
699 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");
700 {
701 // left bond
702 const BondIds Leftids( make_pair(leftnr, rightnr) );
703 BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
704 ASSERT(leftiter != BondsinSceneMap.end(),
705 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
706 +toString(rightnr)+" not on display.");
707 GLMoleculeObject_bond *bondObject = leftiter->second;
708 bondObject->disconnect();
709 BondsinSceneMap.erase(leftiter);
710 delete bondObject; // is done by signal from bond itself
711 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");
712 }
713
714 emit changeOccured();
715}
716
717void GLMoleculeObject_molecule::setVisible(bool value)
718{
719 // first update the mesh if we are going to be visible now
720 if (value)
721 updateTesselationHull();
722 // then emit onward
723 GLMoleculeObject::setVisible(value);
724}
725
726void GLMoleculeObject_molecule::updateTesselationHull()
727{
728 if (!TesselationHullUptodate) {
729 updateMesh(createMoleculeMesh(moleculeid, parent()));
730 TesselationHullUptodate = true;
731 }
732}
733
734std::ostream &operator<<(std::ostream &ost, const GLMoleculeObject_molecule::BondIds &t)
735{
736 ost << t.first << "," << t.second;
737 return ost;
738}
739
740void GLMoleculeObject_molecule::wasClicked()
741{
742 LOG(4, "INFO: GLMoleculeObject_molecule: atom " << moleculeid << " has been clicked");
743 emit moleculeClicked(moleculeid);
744}
Note: See TracBrowser for help on using the repository browser.