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

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

Changed hoverChanged() from mol* to moleculeId_t.

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