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

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

GLMoleculeObject_bond uses ObservedValue for internally representing atom's state.

  • Property mode set to 100644
File size: 24.4 KB
RevLine 
[c67518]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[94d5ac6]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/>.
[c67518]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>
[34e7fdb]43#include <Qt3D/qglbuilder.h>
[c67518]44
45#include "CodePatterns/MemDebug.hpp"
46
47#include "CodePatterns/Assert.hpp"
48#include "CodePatterns/Log.hpp"
49#include "CodePatterns/Observer/Notification.hpp"
[856d05]50#include "CodePatterns/Observer/ObserverLog.hpp"
[c67518]51
52#include "Atom/atom.hpp"
53#include "molecule.hpp"
54#include "Descriptors/AtomIdDescriptor.hpp"
[704d59]55#include "Descriptors/MoleculeIdDescriptor.hpp"
[c67518]56#include "Element/element.hpp"
57#include "LinearAlgebra/Vector.hpp"
[34e7fdb]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"
[c67518]65#include "World.hpp"
66
[8c001a]67#include "GLMoleculeObject_atom.hpp"
68
[704d59]69static QGLSceneNode *createMoleculeMesh(const moleculeId_t molid, QObject *parent)
[34e7fdb]70{
[63fb7a]71 const molecule *molref = const_cast<const World &>(World::getInstance()).
72 getMolecule(MoleculeById(molid));
[704d59]73 if (molref == NULL) {
74 ELOG(1, "Could not createMoleculeMesh, molecule with id " << molid << " already gone.");
75 return NULL;
76 }
[34e7fdb]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);
[b9b49e]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.);
[34e7fdb]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
[704d59]149GLMoleculeObject_molecule::GLMoleculeObject_molecule(QObject *parent, const moleculeId_t molid) :
150 GLMoleculeObject(createMoleculeMesh(molid, parent), parent),
151 Observer(std::string("GLMoleculeObject_molecule")+toString(molid)),
[2b596f]152 isBoundingBoxUptodate(true),
[34e7fdb]153 isSignedOn(false),
[704d59]154 moleculeid(molid),
[7b5984]155 TesselationHullUptodate(true),
[704d59]156 hoverAtomId(-1)
[34e7fdb]157{
158 setMaterial(getMaterial(1));
159 updateBoundingBox();
160
161 // initially, atoms and bonds should be visible
162 m_visible = false;
163
[2b596f]164 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
165 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
[9a7ef9]166
167 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
[34e7fdb]168}
169
[704d59]170GLMoleculeObject_molecule::GLMoleculeObject_molecule(QGLSceneNode *mesh[], QObject *parent, const moleculeId_t molid) :
[bca99d]171 GLMoleculeObject(mesh, parent),
[704d59]172 Observer(std::string("GLMoleculeObject_molecule")+toString(molid)),
[2b596f]173 isBoundingBoxUptodate(true),
[34e7fdb]174 isSignedOn(false),
[704d59]175 moleculeid(molid),
[7b5984]176 TesselationHullUptodate(true),
[704d59]177 hoverAtomId(-1)
[c67518]178{
[3b229e]179 setMaterial(getMaterial(1));
[d6203a]180 updateBoundingBox();
[8c001a]181
[739ee9]182 // initially, atoms and bonds should be visible
183 m_visible = false;
184
[2b596f]185 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
186 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
[9a7ef9]187
188 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
[c67518]189}
190
191GLMoleculeObject_molecule::~GLMoleculeObject_molecule()
192{
[34e7fdb]193 if (isSignedOn) {
[63fb7a]194 const molecule *_molecule = const_cast<const World &>(World::getInstance()).
195 getMolecule(MoleculeById(moleculeid));
[704d59]196 if (_molecule != NULL) {
197 _molecule->signOff(this, molecule::AtomInserted);
198 _molecule->signOff(this, molecule::AtomRemoved);
199 _molecule->signOff(this, molecule::AtomMoved);
200 } else {
201 ELOG(1, "GLMoleculeObject_molecule cannot sign off, molecule with "
202 << moleculeid << " has disappeared.");
203 }
[34e7fdb]204 }
[c67518]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
[73b13c]212void GLMoleculeObject_molecule::activateObserver()
213{
214 // sign on as observer (obtain non-const instance before)
215 const molecule *_molecule = const_cast<const World &>(World::getInstance()).
216 getMolecule(MoleculeById(moleculeid));
217 if (_molecule != NULL) {
218 _molecule->signOn(this, molecule::AtomInserted);
219 _molecule->signOn(this, molecule::AtomRemoved);
220 _molecule->signOn(this, molecule::AtomMoved);
221 isSignedOn = true;
222 } else {
223 ELOG(1, "GLMoleculeObject_molecule() - added null object for not present mol id " << moleculeid);
224 }
225 /*molref->signOn(this, AtomObservable::IndexChanged);
226 molref->signOn(this, AtomObservable::PositionChanged);
227 molref->signOn(this, AtomObservable::ElementChanged);
228 molref->signOn(this, AtomObservable::BondsAdded);*/
229 World::getInstance().signOn(this, World::SelectionChanged);
230}
231
[8c001a]232void GLMoleculeObject_molecule::addAtomBonds(
233 const bond::ptr &_bond,
234 const GLMoleculeObject_bond::SideOfBond _side
235 )
236{
237 bool bond_present = false;
238 const BondIds ids = getBondIds(_bond, _side);
239 // check whether bond is not present already
240 bond_present = BondsinSceneMap.count(ids);
241 if (!bond_present)
242 bondInserted(_bond, _side);
243 else {
244 BondsinSceneMap[ids]->resetPosition();
245 BondsinSceneMap[ids]->resetWidth();
246 }
247}
248
249void GLMoleculeObject_molecule::addAtomBonds(
250 const atom *_atom)
251{
252 const bool atom_present = AtomsinSceneMap.count(_atom->getId());
253 const BondList &bondlist = _atom->getListOfBonds();
254 for (BondList::const_iterator bonditer = bondlist.begin();
255 (bonditer != bondlist.end()) && atom_present;
256 ++bonditer) {
257 const bond::ptr _bond = *bonditer;
258 // check if OtherAtom's sphere is already present
259 const atom *OtherAtom = _bond->GetOtherAtom(_atom);
260 const bool otheratom_present = AtomsinSceneMap.count(OtherAtom->getId());
261 if (otheratom_present && atom_present) {
262 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ?
263 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
264 const GLMoleculeObject_bond::SideOfBond otherside = (_bond->leftatom == _atom) ?
265 GLMoleculeObject_bond::right : GLMoleculeObject_bond::left;
266 addAtomBonds(_bond, side);
267 addAtomBonds(_bond, otherside);
268 }
269 }
270}
271
[d6203a]272void GLMoleculeObject_molecule::updateBoundingBox()
273{
[2b596f]274 isBoundingBoxUptodate = true;
[63fb7a]275 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
276 getMolecule(MoleculeById(moleculeid));
[704d59]277 if (_molecule == NULL) {
278 ELOG(1, "GLMoleculeObject_molecule cannot updateBoundingBox, molecule with "
279 << moleculeid << " has disappeared.");
280 return;
281 }
[aeb694]282 Shape shape = _molecule->getBoundingSphere();
[d6203a]283 Vector v = shape.getCenter();
284 setPosition(QVector3D(v[0], v[1], v[2]));
285 setScale(shape.getRadius() + 0.3); // getBoundingShape() only sees atoms as points, so make the box a bit bigger
286}
287
[c67518]288void GLMoleculeObject_molecule::update(Observable *publisher)
289{
290#ifdef LOG_OBSERVER
[a2a2f7]291 const molecule *_mol = static_cast<molecule *>(publisher);
292 observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(static_cast<Observer *>(this)) << " from molecule "+toString(_mol->getId())+".";
[c67518]293#endif
294}
295
296void GLMoleculeObject_molecule::subjectKilled(Observable *publisher)
[34e7fdb]297{
298 isSignedOn = false;
299}
[c67518]300
301void GLMoleculeObject_molecule::recieveNotification(Observable *publisher, Notification_ptr notification)
302{
[63fb7a]303 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
304 getMolecule(MoleculeById(moleculeid));
[c67518]305 if (publisher == dynamic_cast<const Observable*>(_molecule)){
306 // notofication from atom
307#ifdef LOG_OBSERVER
[708277]308 observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
[c67518]309 << " received notification from molecule " << _molecule->getId() << " for channel "
310 << notification->getChannelNo() << ".";
311#endif
[8c001a]312 switch (notification->getChannelNo()) {
313 case molecule::AtomInserted:
314 {
315 const atomId_t _id = _molecule->lastChanged()->getId();
316 #ifdef LOG_OBSERVER
317 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
318 #endif
[9c259e]319 QMetaObject::invokeMethod(this, // pointer to a QObject
320 "atomInserted", // member name (no parameters here)
321 Qt::QueuedConnection, // connection type
322 Q_ARG(atomId_t, _id)); // parameters
[8c001a]323 break;
324 }
325 case World::AtomRemoved:
326 {
327 const atomId_t _id = _molecule->lastChanged()->getId();
328 #ifdef LOG_OBSERVER
329 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed.";
330 #endif
[9c259e]331 QMetaObject::invokeMethod(this, // pointer to a QObject
332 "atomRemoved", // member name (no parameters here)
333 Qt::QueuedConnection, // connection type
[2f76d2]334 Q_ARG(const atomId_t, _id)); // parameters
[8c001a]335 break;
336 }
[7b5984]337 case molecule::AtomMoved:
338 {
339 #ifdef LOG_OBSERVER
[2b596f]340 const atomId_t _id = _molecule->lastChanged()->getId();
[7b5984]341 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
342 #endif
343 TesselationHullUptodate = false;
[2b596f]344 isBoundingBoxUptodate = false;
[7b5984]345 break;
346 }
[8c001a]347 default:
348 break;
349 }
[c67518]350 }else{
351 // notification from world
352#ifdef LOG_OBSERVER
[708277]353 observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
[c67518]354 << " received notification from world for channel "
355 << notification->getChannelNo() << ".";
356#endif
357 switch (notification->getChannelNo()) {
358 case World::SelectionChanged:
[704d59]359 if (_molecule != NULL) {
360 setSelected(World::getInstance().isSelected(_molecule));
361 } else {
362 ELOG(1, "GLMoleculeObject_molecule cannot change selection, molecule with "
363 << moleculeid << " has disappeared.");
364 }
[c67518]365 break;
366 default:
367 break;
368 }
369 }
370}
371
[8c001a]372void GLMoleculeObject_molecule::initialize(QGLView *view, QGLPainter *painter)
373{
374 // Initialize all of the mesh objects that we have as children.
[2b596f]375 if (m_visible) {
376 GLMoleculeObject::initialize(view, painter);
377 } else {
[8c001a]378 foreach (QObject *obj, children()) {
379 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
380 if (meshobj)
381 meshobj->initialize(view, painter);
382 }
[2b596f]383 }
[8c001a]384}
385
386void GLMoleculeObject_molecule::draw(QGLPainter *painter, const QVector4D &cameraPlane)
387{
[739ee9]388 // draw either molecule's mesh or all atoms and bonds
389 if (m_visible) {
[7b5984]390 updateTesselationHull();
391
[34e7fdb]392 painter->modelViewMatrix().push();
393
394 // Apply the material and effect to the painter.
395 QGLMaterial *material;
396 if (m_hovering)
397 material = m_hoverMaterial;
398 else if (m_selected)
399 material = m_selectionMaterial;
400 else
401 material = m_material;
402
403 ASSERT(material, "GLMoleculeObject::draw: chosen material is NULL");
404
405 painter->setColor(material->diffuseColor());
406 painter->setFaceMaterial(QGL::AllFaces, material);
407 if (m_effect)
408 painter->setUserEffect(m_effect);
409 else
410 painter->setStandardEffect(QGL::LitMaterial);
411
412 // Mark the object for object picking purposes.
413 int prevObjectId = painter->objectPickId();
414 if (m_objectId != -1)
415 painter->setObjectPickId(m_objectId);
416
417 m_mesh[0]->draw(painter);
418
419 // Turn off the user effect, if present.
420 if (m_effect)
421 painter->setStandardEffect(QGL::LitMaterial);
422
423 // Revert to the previous object identifier.
424 painter->setObjectPickId(prevObjectId);
425
426 // Restore the modelview matrix.
427 painter->modelViewMatrix().pop();
428
429 // GLMoleculeObject::draw(painter, cameraPlane);
[739ee9]430 } else {
431 // Draw all of the mesh objects that we have as children.
432 foreach (QObject *obj, children()) {
433 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
434 if (meshobj)
435 meshobj->draw(painter, cameraPlane);
436 }
[2b596f]437
438 // update bounding box prior to selection
439 if (!isBoundingBoxUptodate)
440 updateBoundingBox();
441
442 painter->modelViewMatrix().push();
443 painter->modelViewMatrix().translate(m_position);
444 if (m_rotationAngle != 0.0f)
445 painter->modelViewMatrix().rotate(m_rotationAngle, m_rotationVector);
[f47efd4]446 if ((m_scaleX != 1.0f) || (m_scaleY != 1.0f) || (m_scaleZ != 1.0f))
447 painter->modelViewMatrix().scale(m_scaleX, m_scaleY, m_scaleZ);
[2b596f]448
449 // Draw a box around the mesh, if selected.
450 if (m_selected)
451 drawSelectionBox(painter);
452
453 // Restore the modelview matrix.
454 painter->modelViewMatrix().pop();
[739ee9]455 }
[8c001a]456}
457
458/** Adds an atom of this molecule to the scene.
459 *
460 * @param _atom atom to add
461 */
[2f76d2]462void GLMoleculeObject_molecule::atomInserted(const atomId_t _id)
[8c001a]463{
[9c259e]464 LOG(3, "INFO: GLMoleculeObject_molecule: Received signal atomInserted for atom "+toString(_id)+".");
465
466 TesselationHullUptodate = false;
467 isBoundingBoxUptodate = false;
468
[8923ad8]469 GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(GLMoleculeObject::meshSphere, this, _id);
470 ASSERT( atomObject != NULL,
471 "GLMoleculeObject_molecule::atomInserted - could not create atom object for "+toString(_id));
472 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
473 ASSERT(iter == AtomsinSceneMap.end(),
474 "GLMoleculeObject_molecule::atomInserted - same atom with id "+toString(_id)+" added again.");
475 AtomsinSceneMap.insert( make_pair(_id, atomObject) );
476
477 qRegisterMetaType<atomId_t>("atomId_t");
478 qRegisterMetaType<bond::ptr>("bond::ptr");
479 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
480 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SIGNAL(atomClicked(atomId_t)));
481 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
482 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
483 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
484 connect (atomObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));
485 connect (atomObject, SIGNAL(BondsInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)));
486 connect (atomObject, SIGNAL(indexChanged(GLMoleculeObject_atom*, int, int)), this, SLOT(changeAtomId(GLMoleculeObject_atom*, int, int)));
487
488 isBoundingBoxUptodate = false;
489
490 if (m_objectId == -1)
491 setObjectId(_id);
[8c001a]492
[52cd7b]493 // add all bonds
[f01769]494 const atom * const Walker = const_cast<const World &>(World::getInstance()).
495 getAtom(AtomById(_id));
[704d59]496 if (Walker != NULL)
497 addAtomBonds(Walker);
498 else
499 ELOG(1, "GLMoleculeObject_atom disappeared while about to add bonds.");
[52cd7b]500
[8c001a]501 emit changeOccured();
502}
503
504/** Removes an atom of this molecule from the scene.
505 *
506 * We just the id as the atom might have already been destroyed.
507 *
508 * @param _id id of atom to remove
509 */
[2f76d2]510void GLMoleculeObject_molecule::atomRemoved(const atomId_t _id)
[8c001a]511{
[9c259e]512 LOG(3, "INFO: GLMoleculeObject_molecule: Received signal atomRemoved for atom "+toString(_id)+".");
[8c001a]513 // bonds are removed by signal coming from ~bond
[2b596f]514
[9c259e]515 TesselationHullUptodate = false;
516 isBoundingBoxUptodate = false;
517
[704d59]518 if ((unsigned int)m_objectId == _id)
[2b596f]519 setObjectId(-1);
520
[8c001a]521 // remove atoms
522 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);
523 ASSERT(iter != AtomsinSceneMap.end(),
[73b13c]524 "GLMoleculeObject_molecule::atomRemoved() - atom "+toString(_id)+" not on display.");
[8c001a]525 GLMoleculeObject_atom *atomObject = iter->second;
526 AtomsinSceneMap.erase(iter);
[704d59]527 atomObject->disconnect();
[8c001a]528 delete atomObject;
529
[2b596f]530 isBoundingBoxUptodate = false;
[8c001a]531
532 emit changeOccured();
533}
534
535void GLMoleculeObject_molecule::hoverChangedSignalled(GLMoleculeObject *ob)
536{
537 // Find the atom, ob corresponds to.
[704d59]538 hoverAtomId = -1;
[8c001a]539 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
540 if (atomObject){
541 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
542 if (iter->second == atomObject)
[704d59]543 hoverAtomId = iter->first;
[8c001a]544 }
545
[2b596f]546 // Propagate signal.
[704d59]547 emit hoverChanged(hoverAtomId);
[2b596f]548 } else {
549 // Find the atom, ob corresponds to.
550 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
551 if (moleculeObject == this){
552 // Propagate signal.
[704d59]553 emit hoverChanged(moleculeid, 0);
[2b596f]554 }
555 }
[8c001a]556}
557
558
559/** Helper function to get bond ids in the correct order for BondNodeMap.
560 *
561 * \return pair of ids in correct order.
562 */
563GLMoleculeObject_molecule::BondIds GLMoleculeObject_molecule::getBondIds(
564 const bond::ptr _bond,
565 const enum GLMoleculeObject_bond::SideOfBond _side)
566{
567 BondIds ids;
568 switch (_side) {
569 case GLMoleculeObject_bond::left:
570 ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId());
571 break;
572 case GLMoleculeObject_bond::right:
573 ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId());
574 break;
575 }
576 return ids;
577}
578
579/** Adds a bond to the scene.
580 *
581 * @param _bond bond to add
582 * @param side which side of the bond (left or right)
583 */
584void GLMoleculeObject_molecule::bondInserted(const bond::ptr _bond, const enum GLMoleculeObject_bond::SideOfBond _side)
585{
586 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");
587 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");
588
589 const BondIds ids = getBondIds(_bond, _side);
590 BondNodeMap::iterator iter = BondsinSceneMap.find(ids);
591 if (iter == BondsinSceneMap.end()) {
592 GLMoleculeObject_bond * bondObject =
[009e2e2]593 new GLMoleculeObject_bond(GLMoleculeObject::meshCylinder, this, ids, _side);
[8c001a]594 connect (
595 bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)),
596 this, SLOT(bondRemoved(const atomId_t, const atomId_t)));
597 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
598 BondsinSceneMap.insert( make_pair(ids, bondObject) );
599 // BondIdsinSceneMap.insert( Leftids );
600 } else {
601 iter->second->resetPosition();
602 iter->second->resetWidth();
603 }
604 emit changeOccured();
605}
606
607/** Removes a bond from the scene.
608 *
609 * @param _bond bond to remove
610 */
611void GLMoleculeObject_molecule::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
612{
613 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");
614 {
615 // left bond
616 const BondIds Leftids( make_pair(leftnr, rightnr) );
617 BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
618 ASSERT(leftiter != BondsinSceneMap.end(),
619 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
620 +toString(rightnr)+" not on display.");
621 GLMoleculeObject_bond *bondObject = leftiter->second;
622 bondObject->disconnect();
623 BondsinSceneMap.erase(leftiter);
624 delete bondObject; // is done by signal from bond itself
625 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");
626 }
627
628 emit changeOccured();
629}
630
[34e7fdb]631void GLMoleculeObject_molecule::setVisible(bool value)
632{
633 // first update the mesh if we are going to be visible now
634 if (value)
[7b5984]635 updateTesselationHull();
[34e7fdb]636 // then emit onward
637 GLMoleculeObject::setVisible(value);
638}
639
[7b5984]640void GLMoleculeObject_molecule::updateTesselationHull()
641{
642 if (!TesselationHullUptodate) {
[704d59]643 updateMesh(createMoleculeMesh(moleculeid, parent()));
[7b5984]644 TesselationHullUptodate = true;
645 }
646}
647
[8c001a]648std::ostream &operator<<(std::ostream &ost, const GLMoleculeObject_molecule::BondIds &t)
649{
650 ost << t.first << "," << t.second;
651 return ost;
652}
[34e7fdb]653
[9a7ef9]654void GLMoleculeObject_molecule::wasClicked()
655{
[704d59]656 LOG(4, "INFO: GLMoleculeObject_molecule: atom " << moleculeid << " has been clicked");
657 emit moleculeClicked(moleculeid);
[9a7ef9]658}
[8d3ee6]659
660void GLMoleculeObject_molecule::changeAtomId(GLMoleculeObject_atom *ob, int oldId, int newId)
661{
662 LOG(3, "INFO: GLMoleculeObject_molecule - change atom id " << oldId << " to " << newId << ".");
663
664 // Remove from map.
665 AtomNodeMap::iterator iter = AtomsinSceneMap.find(oldId);
666 ASSERT(iter != AtomsinSceneMap.end(),
667 "GLMoleculeObject_molecule::changeAtomId() - atom with old id "+toString(oldId)+" not on display.");
668 ASSERT(iter->second == ob,
669 "GLMoleculeObject_molecule::changeAtomId() - atom with id "
670 +toString(oldId)+" does not match with object in AtomsinSceneMap.");
671 AtomsinSceneMap.erase(iter);
672
673 // Reinsert with new id.
674 {
675 AtomNodeMap::iterator iter = AtomsinSceneMap.find(newId);
676 ASSERT(iter == AtomsinSceneMap.end(),
677 "GLMoleculeObject_molecule::changeAtomId() - atom with new id "+toString(newId)+" already known.");
678 }
679 AtomsinSceneMap.insert( make_pair(newId, ob) );
680}
Note: See TracBrowser for help on using the repository browser.