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

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

Molecules can be (un)selected by clicking on the tesselation hull.

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