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

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

FIX: GLMoleculeObject_molecule was not informed of atom index change.

  • Property mode set to 100644
File size: 27.5 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, SLOT(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}
745
746void GLMoleculeObject_molecule::changeAtomId(GLMoleculeObject_atom *ob, int oldId, int newId)
747{
748 LOG(3, "INFO: GLMoleculeObject_molecule - change atom id " << oldId << " to " << newId << ".");
749
750 // Remove from map.
751 AtomNodeMap::iterator iter = AtomsinSceneMap.find(oldId);
752 ASSERT(iter != AtomsinSceneMap.end(),
753 "GLMoleculeObject_molecule::changeAtomId() - atom with old id "+toString(oldId)+" not on display.");
754 ASSERT(iter->second == ob,
755 "GLMoleculeObject_molecule::changeAtomId() - atom with id "
756 +toString(oldId)+" does not match with object in AtomsinSceneMap.");
757 AtomsinSceneMap.erase(iter);
758
759 // Reinsert with new id.
760 {
761 AtomNodeMap::iterator iter = AtomsinSceneMap.find(newId);
762 ASSERT(iter == AtomsinSceneMap.end(),
763 "GLMoleculeObject_molecule::changeAtomId() - atom with new id "+toString(newId)+" already known.");
764 }
765 AtomsinSceneMap.insert( make_pair(newId, ob) );
766}
Note: See TracBrowser for help on using the repository browser.