| 1 | /*
 | 
|---|
| 2 |  * Project: MoleCuilder
 | 
|---|
| 3 |  * Description: creates and alters molecular systems
 | 
|---|
| 4 |  * Copyright (C)  2010 University of Bonn. All rights reserved.
 | 
|---|
| 5 |  * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
 | 
|---|
| 6 |  */
 | 
|---|
| 7 | 
 | 
|---|
| 8 | /*
 | 
|---|
| 9 |  * GLWorldScene.cpp
 | 
|---|
| 10 |  *
 | 
|---|
| 11 |  *  This is based on the Qt3D example "teaservice", specifically parts of teaservice.cpp.
 | 
|---|
| 12 |  *
 | 
|---|
| 13 |  *  Created on: Aug 17, 2011
 | 
|---|
| 14 |  *      Author: heber
 | 
|---|
| 15 |  */
 | 
|---|
| 16 | 
 | 
|---|
| 17 | // include config.h
 | 
|---|
| 18 | #ifdef HAVE_CONFIG_H
 | 
|---|
| 19 | #include <config.h>
 | 
|---|
| 20 | #endif
 | 
|---|
| 21 | 
 | 
|---|
| 22 | #include "GLWorldScene.hpp"
 | 
|---|
| 23 | 
 | 
|---|
| 24 | #include "GLMoleculeObject.hpp"
 | 
|---|
| 25 | #include "GLMoleculeObject_atom.hpp"
 | 
|---|
| 26 | #include "GLMoleculeObject_bond.hpp"
 | 
|---|
| 27 | 
 | 
|---|
| 28 | #include "CodePatterns/MemDebug.hpp"
 | 
|---|
| 29 | 
 | 
|---|
| 30 | #include "CodePatterns/Log.hpp"
 | 
|---|
| 31 | 
 | 
|---|
| 32 | #include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp"
 | 
|---|
| 33 | #include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp"
 | 
|---|
| 34 | #include "atom.hpp"
 | 
|---|
| 35 | #include "Bond/bond.hpp"
 | 
|---|
| 36 | #include "Descriptors/AtomIdDescriptor.hpp"
 | 
|---|
| 37 | #include "Helpers/helpers.hpp"
 | 
|---|
| 38 | #include "molecule.hpp"
 | 
|---|
| 39 | #include "World.hpp"
 | 
|---|
| 40 | 
 | 
|---|
| 41 | using namespace MoleCuilder;
 | 
|---|
| 42 | 
 | 
|---|
| 43 | GLWorldScene::GLWorldScene(QObject *parent)
 | 
|---|
| 44 |    : QObject(parent)
 | 
|---|
| 45 | {
 | 
|---|
| 46 |   init();
 | 
|---|
| 47 | 
 | 
|---|
| 48 |   //changeMaterials(false);
 | 
|---|
| 49 | }
 | 
|---|
| 50 | 
 | 
|---|
| 51 | GLWorldScene::~GLWorldScene()
 | 
|---|
| 52 | {
 | 
|---|
| 53 |   // remove all elements
 | 
|---|
| 54 |   GLMoleculeObject::cleanMaterialMap();
 | 
|---|
| 55 | }
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /** Initialise the WorldScene with molecules and atoms from World.
 | 
|---|
| 58 |  *
 | 
|---|
| 59 |  */
 | 
|---|
| 60 | void GLWorldScene::init()
 | 
|---|
| 61 | {
 | 
|---|
| 62 |   const std::vector<molecule*> &molecules = World::getInstance().getAllMolecules();
 | 
|---|
| 63 | 
 | 
|---|
| 64 |   if (molecules.size() > 0) {
 | 
|---|
| 65 |     for (std::vector<molecule*>::const_iterator Runner = molecules.begin();
 | 
|---|
| 66 |         Runner != molecules.end();
 | 
|---|
| 67 |         Runner++) {
 | 
|---|
| 68 |       // create molecule
 | 
|---|
| 69 |       for (molecule::const_iterator atomiter = (*Runner)->begin();
 | 
|---|
| 70 |           atomiter != (*Runner)->end();
 | 
|---|
| 71 |           ++atomiter) {
 | 
|---|
| 72 |         // create atom objects in scene
 | 
|---|
| 73 |         atomInserted(*atomiter);
 | 
|---|
| 74 | 
 | 
|---|
| 75 |         // create bond objects in scene
 | 
|---|
| 76 |         bondsChanged(*atomiter);
 | 
|---|
| 77 |       }
 | 
|---|
| 78 |     }
 | 
|---|
| 79 |   }
 | 
|---|
| 80 | }
 | 
|---|
| 81 | 
 | 
|---|
| 82 | /** Adds an atom to the scene.
 | 
|---|
| 83 |  *
 | 
|---|
| 84 |  * @param _atom atom to add
 | 
|---|
| 85 |  */
 | 
|---|
| 86 | void GLWorldScene::atomInserted(const atom *_atom)
 | 
|---|
| 87 | {
 | 
|---|
| 88 |   LOG(0, "GLWorldScene: Received signal atomInserted for atom "+toString(_atom->getId())+".");
 | 
|---|
| 89 |   GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(this, _atom);
 | 
|---|
| 90 |   AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atom->getId());
 | 
|---|
| 91 |   ASSERT(iter == AtomsinSceneMap.end(),
 | 
|---|
| 92 |       "GLWorldScene::atomAdded() - same atom "+_atom->getName()+" added again.");
 | 
|---|
| 93 |   AtomsinSceneMap.insert( make_pair(_atom->getId(), atomObject) );
 | 
|---|
| 94 |   connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(atomClicked(atomId_t)));
 | 
|---|
| 95 |   connect (atomObject, SIGNAL(hoverChanged()), this, SIGNAL(changed()));
 | 
|---|
| 96 |   connect (atomObject, SIGNAL(BondsChanged(const atom *)), this, SLOT(bondsChanged(const atom *)));
 | 
|---|
| 97 |   bondsChanged(_atom);
 | 
|---|
| 98 |   emit changeOccured();
 | 
|---|
| 99 | }
 | 
|---|
| 100 | 
 | 
|---|
| 101 | /** Removes an atom from the scene.
 | 
|---|
| 102 |  *
 | 
|---|
| 103 |  * @param _atom atom to remove
 | 
|---|
| 104 |  */
 | 
|---|
| 105 | void GLWorldScene::atomRemoved(const atom *_atom)
 | 
|---|
| 106 | {
 | 
|---|
| 107 |   LOG(0, "GLWorldScene: Received signal atomRemoved for atom "+toString(_atom->getId())+".");
 | 
|---|
| 108 |   // remove all its bonds
 | 
|---|
| 109 |   const BondList& bondlist = _atom->getListOfBonds();
 | 
|---|
| 110 |   for (BondList::const_iterator iter = bondlist.begin(); iter != bondlist.end(); ++iter) {
 | 
|---|
| 111 |     bondRemoved((*iter)->leftatom->getId(), (*iter)->rightatom->getId());
 | 
|---|
| 112 |     bondRemoved((*iter)->rightatom->getId(), (*iter)->leftatom->getId());
 | 
|---|
| 113 |   }
 | 
|---|
| 114 |   // remove atoms
 | 
|---|
| 115 |   AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atom->getId());
 | 
|---|
| 116 |   ASSERT(iter != AtomsinSceneMap.end(),
 | 
|---|
| 117 |       "GLWorldScene::atomRemoved() - atom "+_atom->getName()+" not on display.");
 | 
|---|
| 118 |   GLMoleculeObject_atom *atomObject = iter->second;
 | 
|---|
| 119 |   atomObject->disconnect();
 | 
|---|
| 120 |   AtomsinSceneMap.erase(iter);
 | 
|---|
| 121 |   delete atomObject;
 | 
|---|
| 122 |   emit changeOccured();
 | 
|---|
| 123 | }
 | 
|---|
| 124 | 
 | 
|---|
| 125 | /** Updates the bond structure of the signaled \a _atom.
 | 
|---|
| 126 |  *
 | 
|---|
| 127 |  * @param _atom atom whose bonds changed.
 | 
|---|
| 128 |  */
 | 
|---|
| 129 | void GLWorldScene::bondsChanged(const atom *_atom)
 | 
|---|
| 130 | {
 | 
|---|
| 131 |   const atomId_t id = _atom->getId();
 | 
|---|
| 132 | 
 | 
|---|
| 133 |   // create list with all present bonds
 | 
|---|
| 134 |   std::set< atomId_t > presentBonds;
 | 
|---|
| 135 |   std::pair< BondIdsMap::const_iterator, BondIdsMap::const_iterator> range =
 | 
|---|
| 136 |       BondIdsinSceneMap.equal_range( id );
 | 
|---|
| 137 |   for (BondIdsMap::const_iterator iter = range.first; iter != range.second; ++iter) {
 | 
|---|
| 138 |     const atomId_t otherid = iter->second;
 | 
|---|
| 139 | #ifndef NDEBUG
 | 
|---|
| 140 |     std::set< atomId_t >::const_iterator iter = presentBonds.find(otherid);
 | 
|---|
| 141 |     ASSERT(iter == presentBonds.end(),
 | 
|---|
| 142 |         "GLWorldScene::BondsChanged() - bond id "+toString(otherid)+" for atom "
 | 
|---|
| 143 |         +toString(id)+" present twice.");
 | 
|---|
| 144 | #endif
 | 
|---|
| 145 |     presentBonds.insert( otherid );
 | 
|---|
| 146 |   }
 | 
|---|
| 147 |   LOG(0, "We have the following bonds: "+toString(presentBonds)+".");
 | 
|---|
| 148 | 
 | 
|---|
| 149 |   // search for added bonds
 | 
|---|
| 150 |   const BondList &bondlist = _atom->getListOfBonds();
 | 
|---|
| 151 |   for (BondList::const_iterator bonditer = bondlist.begin();
 | 
|---|
| 152 |       bonditer != bondlist.end();
 | 
|---|
| 153 |       ++bonditer) {
 | 
|---|
| 154 |     const bond *_bond = *bonditer;
 | 
|---|
| 155 |     const atomId_t otherid = _bond->GetOtherAtom(_atom)->getId();
 | 
|---|
| 156 |     const BondIds ids = std::make_pair( id, otherid );
 | 
|---|
| 157 |     BondNodeMap::const_iterator iter = BondsinSceneMap.find(ids);
 | 
|---|
| 158 |     if (iter != BondsinSceneMap.end()) {
 | 
|---|
| 159 |       // bond is already present
 | 
|---|
| 160 |       std::set< atomId_t >::const_iterator iter = presentBonds.find(otherid);
 | 
|---|
| 161 |       ASSERT(iter != presentBonds.end(),
 | 
|---|
| 162 |           "GLWorldScene::BondsChanged() - other id "+toString(otherid)+" for atom "
 | 
|---|
| 163 |           +toString(_atom->getId())+" not present in BondIdsinSceneMap.");
 | 
|---|
| 164 |       presentBonds.erase(otherid);
 | 
|---|
| 165 |       LOG(0, "Removing "+toString(otherid)+" from presentBonds.");
 | 
|---|
| 166 |     } else {
 | 
|---|
| 167 |       // insert new bond
 | 
|---|
| 168 |       bondInserted(_bond);
 | 
|---|
| 169 |     }
 | 
|---|
| 170 |   }
 | 
|---|
| 171 |   LOG(0, "The following bonds should not be present: "+toString(presentBonds)+".");
 | 
|---|
| 172 | 
 | 
|---|
| 173 |   // remove all still presentBonds
 | 
|---|
| 174 |   for (std::set< atomId_t >::iterator iter = presentBonds.begin();
 | 
|---|
| 175 |       !presentBonds.empty(); iter = presentBonds.begin()) {
 | 
|---|
| 176 |     bondRemoved( id, *iter );
 | 
|---|
| 177 |   }
 | 
|---|
| 178 | }
 | 
|---|
| 179 | 
 | 
|---|
| 180 | /** Adds a bond to the scene.
 | 
|---|
| 181 |  *
 | 
|---|
| 182 |  * @param _bond bond to add
 | 
|---|
| 183 |  */
 | 
|---|
| 184 | void GLWorldScene::bondInserted(const bond *_bond)
 | 
|---|
| 185 | {
 | 
|---|
| 186 |   LOG(0, "GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");
 | 
|---|
| 187 |   const double distance =
 | 
|---|
| 188 |       _bond->leftatom->getPosition().distance(_bond->rightatom->getPosition())/2.;
 | 
|---|
| 189 |   {
 | 
|---|
| 190 |     // left bond
 | 
|---|
| 191 |     const BondIds Leftids( make_pair(_bond->leftatom->getId(), _bond->rightatom->getId()) );
 | 
|---|
| 192 |     BondNodeMap::iterator iter = BondsinSceneMap.find(Leftids);
 | 
|---|
| 193 |     ASSERT(iter == BondsinSceneMap.end(),
 | 
|---|
| 194 |         "GLWorldScene::bondAdded() - same left-sided bond "+toString(*_bond)+" added again.");
 | 
|---|
| 195 |     GLMoleculeObject_bond *bondObject =
 | 
|---|
| 196 |         new GLMoleculeObject_bond(this, _bond, distance, GLMoleculeObject_bond::left);
 | 
|---|
| 197 |     BondsinSceneMap.insert( make_pair(Leftids, bondObject) );
 | 
|---|
| 198 |     BondIdsinSceneMap.insert( Leftids );
 | 
|---|
| 199 |   }
 | 
|---|
| 200 |   {
 | 
|---|
| 201 |     // right bond
 | 
|---|
| 202 |     const BondIds Rightids( make_pair(_bond->rightatom->getId(), _bond->leftatom->getId()) );
 | 
|---|
| 203 |     BondNodeMap::iterator iter = BondsinSceneMap.find(Rightids);
 | 
|---|
| 204 |     ASSERT(iter == BondsinSceneMap.end(),
 | 
|---|
| 205 |         "GLWorldScene::bondAdded() - same right-sided bond "+toString(*_bond)+" added again.");
 | 
|---|
| 206 |     GLMoleculeObject_bond *bondObject =
 | 
|---|
| 207 |         new GLMoleculeObject_bond(this, _bond, distance, GLMoleculeObject_bond::right);
 | 
|---|
| 208 |     BondsinSceneMap.insert( make_pair(Rightids, bondObject) );
 | 
|---|
| 209 |     BondIdsinSceneMap.insert( Rightids );
 | 
|---|
| 210 |   }
 | 
|---|
| 211 |   emit changeOccured();
 | 
|---|
| 212 | }
 | 
|---|
| 213 | 
 | 
|---|
| 214 | /** Removes a bond from the scene.
 | 
|---|
| 215 |  *
 | 
|---|
| 216 |  * @param _bond bond to remove
 | 
|---|
| 217 |  */
 | 
|---|
| 218 | void GLWorldScene::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)
 | 
|---|
| 219 | {
 | 
|---|
| 220 |   LOG(0, "GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(leftnr)+".");
 | 
|---|
| 221 |   {
 | 
|---|
| 222 |     // left bond
 | 
|---|
| 223 |     const BondIds Leftids( make_pair(leftnr, rightnr) );
 | 
|---|
| 224 |     BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );
 | 
|---|
| 225 |     ASSERT(leftiter != BondsinSceneMap.end(),
 | 
|---|
| 226 |         "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"
 | 
|---|
| 227 |         +toString(rightnr)+" not on display.");
 | 
|---|
| 228 |     GLMoleculeObject_bond *bondObject = leftiter->second;
 | 
|---|
| 229 |     BondsinSceneMap.erase(leftiter);
 | 
|---|
| 230 |     delete bondObject;
 | 
|---|
| 231 |   }
 | 
|---|
| 232 |   // remove from bond ids
 | 
|---|
| 233 |   std::pair<BondIdsMap::iterator, BondIdsMap::iterator> leftrange =
 | 
|---|
| 234 |       BondIdsinSceneMap.equal_range(leftnr);
 | 
|---|
| 235 |   BondIdsMap::iterator iter;
 | 
|---|
| 236 |   for (iter = leftrange.first; iter != leftrange.second; ++iter) {
 | 
|---|
| 237 |     if (iter->second == rightnr) {
 | 
|---|
| 238 |       BondIdsinSceneMap.erase(iter);
 | 
|---|
| 239 |       break;
 | 
|---|
| 240 |     }
 | 
|---|
| 241 |   }
 | 
|---|
| 242 |   ASSERT(iter != leftrange.second,
 | 
|---|
| 243 |       "GLWorldScene::bondRemoved() - could not find ("
 | 
|---|
| 244 |       +toString(leftnr)+"-"+toString(rightnr)+" in BondIdsinSceneMap.");
 | 
|---|
| 245 |   emit changeOccured();
 | 
|---|
| 246 | }
 | 
|---|
| 247 | 
 | 
|---|
| 248 | void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
 | 
|---|
| 249 | {
 | 
|---|
| 250 |   // Initialize all of the mesh objects that we have as children.
 | 
|---|
| 251 |    foreach (QObject *obj, children()) {
 | 
|---|
| 252 |      GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
 | 
|---|
| 253 |        if (meshobj)
 | 
|---|
| 254 |          meshobj->initialize(view, painter);
 | 
|---|
| 255 |    }
 | 
|---|
| 256 | }
 | 
|---|
| 257 | 
 | 
|---|
| 258 | void GLWorldScene::draw(QGLPainter *painter) const
 | 
|---|
| 259 | {
 | 
|---|
| 260 |    // Draw all of the mesh objects that we have as children.
 | 
|---|
| 261 |    foreach (QObject *obj, children()) {
 | 
|---|
| 262 |      GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
 | 
|---|
| 263 |        if (meshobj)
 | 
|---|
| 264 |          meshobj->draw(painter);
 | 
|---|
| 265 |    }
 | 
|---|
| 266 | }
 | 
|---|
| 267 | 
 | 
|---|
| 268 | void GLWorldScene::atomClicked(atomId_t no)
 | 
|---|
| 269 | {
 | 
|---|
| 270 |    qDebug("GLWorldScene: atom %d has been clicked.", no);
 | 
|---|
| 271 |    const atom *Walker = World::getInstance().getAtom(AtomById(no));
 | 
|---|
| 272 |    if (!World::getInstance().isSelected(Walker))
 | 
|---|
| 273 |    SelectionAtomById(no);
 | 
|---|
| 274 |    else
 | 
|---|
| 275 |      SelectionNotAtomById(no);
 | 
|---|
| 276 |    emit clicked(no);
 | 
|---|
| 277 | }
 | 
|---|
| 278 | 
 | 
|---|