/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Copyright (C) 2013 Frederik Heber. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * GLWorldScene.cpp * * This is based on the Qt3D example "teaservice", specifically parts of teaservice.cpp. * * Created on: Aug 17, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "GLWorldScene.hpp" #include #include #include #include #include #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject.hpp" #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.hpp" #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_bond.hpp" #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.hpp" #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_shape.hpp" #include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp" #include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Log.hpp" #include #include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp" #include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp" #include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp" #include "Actions/SelectionAction/Molecules/NotMoleculeByIdAction.hpp" #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "Descriptors/AtomIdDescriptor.hpp" #include "Descriptors/MoleculeIdDescriptor.hpp" #include "Helpers/helpers.hpp" #include "Shapes/ShapeRegistry.hpp" #include "molecule.hpp" #include "World.hpp" #include using namespace MoleCuilder; // static functions static void eraseBondNodeParents( std::vector &_BondNodeParentMaps, const ObservedValue_Index_t &_bondid) { const size_t left_erased = _BondNodeParentMaps[0].left.erase(_bondid); const size_t right_erased = _BondNodeParentMaps[1].left.erase(_bondid); ASSERT( (left_erased == 1) && (right_erased == 1), "eraseBondNodeParents() - could not erase both parents of "+toString(_bondid)+"?"); } /** Checks whether both parents of the bond are set to GLWorldScene and the * bondRemoved() signals was received for this bond. * * \param _BondNodeParent_Maps - map containing parents * \param _ToBeRemovedNodes - set with all bonds that are to be removed * \param _bondid id of bond * \return true - both parents are assigned to GLWorldScene, false - else */ static bool checkBondRemoval( const std::vector &_BondNodeParentMaps, const GLWorldScene::ToBeRemovedNodes_t &_ToBeRemovedNodes, const ObservedValue_Index_t &_bondid) { GLWorldScene::BondNodeParentMap_t::left_const_iterator leftiter = _BondNodeParentMaps[0].left.find(_bondid); GLWorldScene::BondNodeParentMap_t::left_const_iterator rightiter = _BondNodeParentMaps[1].left.find(_bondid); ASSERT( leftiter != _BondNodeParentMaps[0].left.end(), "checkBondRemoval() - left parent to index "+toString(_bondid)+" missing?"); ASSERT( rightiter != _BondNodeParentMaps[1].left.end(), "checkBondRemoval() - right parent to index "+toString(_bondid)+" missing?"); return ((leftiter->second == (ObservedValue_Index_t)NULL) && (rightiter->second == (ObservedValue_Index_t)NULL) && (_ToBeRemovedNodes.count(_bondid))); } void removeBondFromScene( GLWorldScene::BondNodeMap &_BondsinSceneMap, const ObservedValue_Index_t &_bondid) { std::pair iters = _BondsinSceneMap.equal_range(_bondid); ASSERT( iters.first != iters.second, "removeBondFromScene() - could not find bond to id "+toString(_bondid)); for (GLWorldScene::BondNodeMap::iterator iter = iters.first; iter != iters.second; ++iter) { GLMoleculeObject_bond *bondObject = iter->second; delete bondObject; // is done by signal from bond itself //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << "."); } _BondsinSceneMap.erase(_bondid); } static bool checkAtomRemoval( const GLWorldScene::AtomNodeParentMap_t &_AtomNodeParentMap, const GLWorldScene::ToBeRemovedNodes_t &_ToBeRemovedNodes, const ObservedValue_Index_t &_atomid) { GLWorldScene::AtomNodeParentMap_t::left_const_iterator iter = _AtomNodeParentMap.left.find(_atomid); ASSERT( iter != _AtomNodeParentMap.left.end(), "checkAtomRemoval() - missing parent entry for "+toString(_atomid)); return ((iter->second == (ObservedValue_Index_t)NULL) && (_ToBeRemovedNodes.count(_atomid))); } // class definitions GLWorldScene::GLWorldScene( QtObservedInstanceBoard * _board, QObject *parent) : QObject(parent), BondNodeParentMaps(std::vector(2)), selectionMode(SelectAtom), board(_board) { qRegisterMetaType("atomId_t"); qRegisterMetaType("GLMoleculeObject_bond::SideOfBond"); int sphereDetails[] = {5, 3, 2, 0}; int cylinderDetails[] = {16, 8, 6, 3}; for (int i=0;isetOption(QGLSceneNode::CullBoundingBox, true); QGLBuilder cylinderBuilder; cylinderBuilder << QGLCylinder(.25,.25,1.0,cylinderDetails[i]); GLMoleculeObject::meshCylinder[i] = cylinderBuilder.finalizedSceneNode(); GLMoleculeObject::meshCylinder[i]->setOption(QGLSceneNode::CullBoundingBox, true); } connect(board, SIGNAL(moleculeInserted(QtObservedMolecule::ptr)), this, SLOT(insertMolecule(QtObservedMolecule::ptr))); connect(board, SIGNAL(moleculeRemoved(ObservedValue_Index_t)), this, SLOT(removeMolecule(ObservedValue_Index_t))); connect(board, SIGNAL(atomInserted(QtObservedAtom::ptr)), this, SLOT(connectAtom(QtObservedAtom::ptr)), Qt::DirectConnection); connect(this, SIGNAL(atomConnected(QtObservedAtom::ptr)), this, SLOT(insertAtom(QtObservedAtom::ptr))); connect(board, SIGNAL(atomRemoved(ObservedValue_Index_t)), this, SLOT(removeAtom(ObservedValue_Index_t))); connect(board, SIGNAL(bondInserted(QtObservedBond::ptr)), this, SLOT(connectBond(QtObservedBond::ptr)), Qt::DirectConnection); connect(this, SIGNAL(bondConnected(QtObservedBond::ptr)), this, SLOT(insertBond(QtObservedBond::ptr))); connect(board, SIGNAL(bondRemoved(ObservedValue_Index_t)), this, SLOT(removeBond(ObservedValue_Index_t))); // connect(this, SIGNAL(updated()), this, SLOT(update())); } GLWorldScene::~GLWorldScene() { // remove all elements GLMoleculeObject::cleanMaterialMap(); } void GLWorldScene::clickAtom(atomId_t no) { LOG(3, "INFO: GLWorldScene - atom " << no << " has been clicked."); const atom * const Walker = const_cast(World::getInstance()). getAtom(AtomById(no)); ASSERT( Walker != NULL, "GLWorldScene::clickAtom() - clicked atom has disappeared."); if (selectionMode == SelectAtom){ if (!World::getInstance().isSelected(Walker)) SelectionAtomById(std::vector(1,no)); else SelectionNotAtomById(std::vector(1,no)); }else if (selectionMode == SelectMolecule){ const molecule *mol = Walker->getMolecule(); ASSERT(mol, "Atom without molecule has been clicked."); molids_t ids(1, mol->getId()); if (!World::getInstance().isSelected(mol)) SelectionMoleculeById(ids); else SelectionNotMoleculeById(ids); } emit clicked(no); } /** Prepares adding an atom to the scene * * We need to listen to moleculeChanged() in order to properly re-parent() * this QObject * * @param _atom atom to connect */ void GLWorldScene::connectAtom(QtObservedAtom::ptr _atom) { connect(_atom.get(), SIGNAL(moleculeChanged()), this, SLOT(reparentAtom())); boost::recursive_mutex::scoped_lock lock(Atom_mutex); // store the object, as we need it on reparenting const ObservedValue_Index_t atomid = _atom->getIndex(); #ifndef NDEBUG std::pair< ObservedAtoms_t::iterator, bool > inserter = #endif ObservedAtoms.insert( std::make_pair(_atom.get(), _atom) ); ASSERT( inserter.second, "GLWorldScene::connectAtom() - observed atom "+toString(_atom)+" already stored?"); #ifndef NDEBUG std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter = #endif ObservedValueIndexLookup.insert( std::make_pair(atomid, _atom.get()) ); ASSERT( indexinserter.second, "GLWorldScene::connectAtom() - observed atom's index " +toString(atomid)+" already stored?"); // and create entry in the parent map AtomNodeParentMap.left.insert( std::make_pair(atomid, (ObservedValue_Index_t)NULL) ); emit atomConnected(_atom); } /** Adds an atom to the scene. * * @param _atom atom to add */ void GLWorldScene::insertAtom(QtObservedAtom::ptr _atom) { LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom " << _atom->getAtomIndex()); boost::recursive_mutex::scoped_lock lock(Atom_mutex); const ObservedValue_Index_t atomid = _atom->getIndex(); QObject *parent = static_cast(this); GLMoleculeObject_atom *atomObject = NULL; { AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(atomid); ASSERT (parentiter != AtomNodeParentMap.left.end(), "GLWorldScene::insertAtom() - parent to atom id "+toString(atomid)+" unknown?"); const ObservedValue_Index_t parentindex = parentiter->second; if (parentindex != (ObservedValue_Index_t)NULL) { const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentindex); if (moliter != MoleculesinSceneMap.end()) parent = moliter->second; } atomObject = new GLMoleculeObject_atom( GLMoleculeObject::meshSphere, parent, _atom); ASSERT( atomObject != NULL, "GLWorldScene::atomInserted - could not create atom object for " +toString(_atom->getAtomIndex())); } AtomNodeMap::iterator iter = AtomsinSceneMap.find(atomid); ASSERT(iter == AtomsinSceneMap.end(), "GLWorldScene::insertAtom - same atom with id " +toString(_atom->getAtomIndex())+" added again."); AtomsinSceneMap.insert( make_pair(atomid, atomObject) ); connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(clickAtom(atomId_t))); connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed())); connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed())); connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *))); emit changed(); emit changeOccured(); } template void removeStoredObservedValue( GLWorldScene::ObservedValueIndexLookup_t &_ObservedValueIndexLookup, T &_ObservedValues, const ObservedValue_Index_t &_id) { // get QObject* from lookup const GLWorldScene::ObservedValueIndexLookup_t::iterator iter = _ObservedValueIndexLookup.find(_id); ASSERT( iter != _ObservedValueIndexLookup.end(), "removeStoredObservedValue() - could not find index "+toString(_id) +" to stored observed value."); QObject * sender = iter->second; const size_t erased = _ObservedValues.erase(sender); ASSERT( erased == 1, "removeStoredObservedValue() - could not erase stored observed value " +toString(_id)); _ObservedValueIndexLookup.erase(iter); } void removeAtomFromScene( GLWorldScene::AtomNodeMap &_AtomsinSceneMap, const ObservedValue_Index_t &_atomid) { GLWorldScene::AtomNodeMap::iterator iter = _AtomsinSceneMap.find(_atomid); ASSERT(iter != _AtomsinSceneMap.end(), "removeAtomFromScene() - atom "+toString(_atomid)+" not on display."); GLMoleculeObject_atom *atomObject = iter->second; _AtomsinSceneMap.erase(iter); delete atomObject; } void GLWorldScene::checkAndRemoveAtom(const ObservedValue_Index_t &_atomid) { boost::recursive_mutex::scoped_lock lock(Atom_mutex); if (checkAtomRemoval(AtomNodeParentMap, ToBeRemovedNodes, _atomid)) { LOG(4, "DEBUG: Found parent of to be removed atom as GLWorldScene, removing."); removeAtomFromScene(AtomsinSceneMap, _atomid); AtomNodeParentMap.left.erase(_atomid); ToBeRemovedNodes.erase(_atomid); removeStoredObservedValue(ObservedValueIndexLookup, ObservedAtoms, _atomid); } } /** Removes an atom. * * @param _atomid index of the atom that is removed */ void GLWorldScene::removeAtom(ObservedValue_Index_t _atomid) { LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atomid)+"."); // bonds are removed by signal coming from ~bond boost::recursive_mutex::scoped_lock lock(Atom_mutex); ASSERT( ToBeRemovedNodes.count(_atomid) == 0, "GLWorldScene::removeAtom() - removedAtom signal for id "+toString(_atomid) +" came in twice?"); ToBeRemovedNodes.insert( _atomid ); // remove atoms checkAndRemoveAtom( _atomid ); emit changed(); emit changeOccured(); } /** Prepares adding a bond to the scene * * We need to listen to moleculeChanged() in order to properly re-parent() * this QObject * * @param _bond bond to connect */ void GLWorldScene::connectBond(QtObservedBond::ptr _bond) { LOG(3, "INFO: GLWorldScene::connectBond() - connecting to bonds " << _bond->getBondIndex()); connect(_bond.get(), SIGNAL(leftmoleculeChanged()), this, SLOT(reparentBondLeft()), Qt::QueuedConnection); connect(_bond.get(), SIGNAL(rightmoleculeChanged()), this, SLOT(reparentBondRight()), Qt::QueuedConnection); boost::recursive_mutex::scoped_lock lock(Bond_mutex); // store the object, as we need it on reparenting const ObservedValue_Index_t bondid = _bond->getIndex(); { #ifndef NDEBUG std::pair< ObservedBonds_t::iterator, bool > inserter = #endif ObservedBonds.insert( std::make_pair(_bond.get(), _bond) ); ASSERT( inserter.second, "GLWorldScene::connectBond() - observed bond "+toString(_bond)+" already stored?"); #ifndef NDEBUG std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter = #endif ObservedValueIndexLookup.insert( std::make_pair(bondid, _bond.get()) ); ASSERT( indexinserter.second, "GLWorldScene::connectBond() - observed bond's index " +toString(bondid)+" already stored?"); } { if ((_bond->getLeftAtom() != NULL) && (_bond->getLeftAtom()->getMoleculeRef() != NULL)) BondNodeParentMaps[0].left.insert( std::make_pair(bondid, _bond->getLeftAtom()->getMoleculeRef()->getIndex()) ); else BondNodeParentMaps[0].left.insert( std::make_pair(bondid, (ObservedValue_Index_t)NULL) ); if ((_bond->getRightAtom() != NULL) && (_bond->getRightAtom()->getMoleculeRef() != NULL)) BondNodeParentMaps[1].left.insert( std::make_pair(bondid, _bond->getRightAtom()->getMoleculeRef()->getIndex()) ); else BondNodeParentMaps[1].left.insert( std::make_pair(bondid, (ObservedValue_Index_t)NULL) ); } emit bondConnected(_bond); } /** Adds a bond to the scene. * * @param _bond bond to add */ void GLWorldScene::insertBond(QtObservedBond::ptr _bond) { boost::recursive_mutex::scoped_lock lock(Bond_mutex); const std::vector< GLMoleculeObject_bond::SideOfBond > bondsides = boost::assign::list_of (GLMoleculeObject_bond::left) (GLMoleculeObject_bond::right); LOG(3, "INFO: GLWorldScene::insertBond() - Adding bonds " << _bond->getBondIndex()); const ObservedValue_Index_t bondid = _bond->getIndex(); #ifdef NDEBUG BondNodeMap::iterator iter = BondsinSceneMap.find(bondid); ASSERT( iter == BondsinSceneMap.end(), "GLWorldScene::insertBond() - bond "+toString(bondid)+" is already known."); #endif { for (size_t i=0;i<2;++i) { BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[i].left.find(bondid); ASSERT (parentiter != BondNodeParentMaps[i].left.end(), "GLWorldScene::insertBond() - parent to bond id "+toString(bondid)+" unknown?"); QObject *parent = this; if (parentiter->second != (ObservedValue_Index_t)NULL) { const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentiter->second); if (moliter != MoleculesinSceneMap.end()) parent = moliter->second; } GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond( GLMoleculeObject::meshCylinder, parent, _bond, bondsides[i]); connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed())); BondsinSceneMap.insert( std::make_pair(bondid, bondObject) ); } } emit changed(); emit changeOccured(); } void GLWorldScene::checkAndRemoveBond(const ObservedValue_Index_t &_bondid) { boost::recursive_mutex::scoped_lock lock(Bond_mutex); if (checkBondRemoval(BondNodeParentMaps, ToBeRemovedNodes, _bondid)) { LOG(3, "DEBUG: Found both parents of to be removed bond " << _bondid << " as GLWorldScene, removing."); removeBondFromScene(BondsinSceneMap, _bondid); removeStoredObservedValue(ObservedValueIndexLookup, ObservedBonds, _bondid); eraseBondNodeParents(BondNodeParentMaps, _bondid); ToBeRemovedNodes.erase(_bondid); } } /** Removes a bond. * * @param _bondid id of bond to remove */ void GLWorldScene::removeBond(ObservedValue_Index_t _bondid) { boost::recursive_mutex::scoped_lock lock(Bond_mutex); LOG(3, "INFO: GLWorldScene::removedBond() - got bondRemoved signal from board for id " << _bondid); ASSERT( ToBeRemovedNodes.find(_bondid) == ToBeRemovedNodes.end(), "GLWorldScene::removeBond() - bondRemoved for "+toString(_bondid)+" obtained twice?"); ToBeRemovedNodes.insert( _bondid ); // check whether node has still non-NULL parents, otherwise remove completely checkAndRemoveBond( _bondid ); emit changed(); emit changeOccured(); } void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob) { boost::recursive_mutex::scoped_lock lock(Atom_mutex); // Find the atom, ob corresponds to. hoverAtomId = -1; GLMoleculeObject_atom *atomObject = dynamic_cast(ob); if (atomObject){ for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){ if (iter->second == atomObject) hoverAtomId = iter->second->objectId(); } // Propagate signal. emit hoverChanged(hoverAtomId); } else { // Find the atom, ob corresponds to. GLMoleculeObject_molecule *moleculeObject = dynamic_cast(ob); if (moleculeObject){ // Propagate signal. emit hoverChanged(moleculeObject->objectId(), 0); } } } void GLWorldScene::clickMolecule(moleculeId_t no) { LOG(3, "INFO: GLMoleculeObject_molecule - mol " << no << " has been clicked."); const molecule * const mol= const_cast(World::getInstance()). getMolecule(MoleculeById(no)); ASSERT(mol, "Atom without molecule has been clicked."); molids_t ids(1, mol->getId()); if (!World::getInstance().isSelected(mol)) SelectionMoleculeById(ids); else SelectionNotMoleculeById(ids); emit clicked(no); } /** Inserts a molecule into the scene. * * @param _mol molecule to insert */ void GLWorldScene::insertMolecule(QtObservedMolecule::ptr _mol) { const ObservedValue_Index_t molid = _mol->getIndex(); LOG(3, "INFO: GLWorldScene: Received signal moleculeInserted for molecule " << _mol->getMolIndex()); MoleculeNodeMap::const_iterator iter = MoleculesinSceneMap.find(molid); ASSERT( iter == MoleculesinSceneMap.end(), "GLWorldScene::insertMolecule() - molecule's id "+toString(molid) +" already present."); // add new object LOG(1, "DEBUG: Adding GLMoleculeObject_molecule to id " << molid); GLMoleculeObject_molecule *molObject = new GLMoleculeObject_molecule( GLMoleculeObject::meshEmpty, this, _mol); ASSERT( molObject != NULL, "GLWorldScene::insertMolecule - could not create molecule object for " +toString(molid)); #ifndef NDEBUG foreach (QObject *obj, molObject->children()) { GLMoleculeObject *meshobj = qobject_cast(obj); ASSERT( meshobj == NULL, "GLWorldScene::insertMolecule() - there are already atoms or bonds attached to a to molecule."); } #endif // check all atoms for not yet assigned parents { boost::recursive_mutex::scoped_lock lock(Atom_mutex); std::pair iters = AtomNodeParentMap.right.equal_range(molid); for (AtomNodeParentMap_t::right_const_iterator iter = iters.first; iter != iters.second; ++iter) { AtomNodeMap::const_iterator atomiter = AtomsinSceneMap.find(iter->second); if (atomiter != AtomsinSceneMap.end()) resetParent(atomiter->second, molObject); } } // check all bonds for not yet assigned parents { boost::recursive_mutex::scoped_lock lock(Bond_mutex); for (size_t i=0;i<2;++i) { std::pair iters = BondNodeParentMaps[i].right.equal_range(molid); for (BondNodeParentMap_t::right_const_iterator iter = iters.first; iter != iters.second; ++iter) { BondNodeMap::const_iterator bonditer = BondsinSceneMap.find(iter->second); if (bonditer != BondsinSceneMap.end()) resetParent(bonditer->second, molObject); } } } #ifndef NDEBUG std::pair inserter = #endif MoleculesinSceneMap.insert( make_pair(molid, molObject) ); ASSERT(inserter.second, "GLWorldScene::insertMolecule() - molecule "+toString(_mol->getMolIndex()) +" already present in scene."); connect (molObject, SIGNAL(changed()), this, SIGNAL(changed())); connect (molObject, SIGNAL(changeOccured()), this, SIGNAL(changeOccured())); emit changed(); emit changeOccured(); } /** Removes a molecule from the scene. * * @param _molid index of the molecule to remove */ void GLWorldScene::removeMolecule(ObservedValue_Index_t _molid) { LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molid)+"."); MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molid); ASSERT ( iter != MoleculesinSceneMap.end(), "GLWorldScene::removeMolecule() - to be removed molecule "+toString(_molid) +" is already gone."); GLMoleculeObject_molecule *molObject = iter->second; // check for any atoms and bonds still attached to it #ifndef NDEBUG foreach (QObject *obj, molObject->children()) { GLMoleculeObject *meshobj = qobject_cast(obj); ASSERT( meshobj == NULL, "GLWorldScene::removeMolecule() - there are still atoms or bonds attached to a to molecule."); } #endif // finally, remove molecule delete molObject; MoleculesinSceneMap.erase(iter); emit changed(); emit changeOccured(); } void GLWorldScene::moleculesVisibilityChanged(ObservedValue_Index_t _id, bool _visible) { MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id); ASSERT( iter != MoleculesinSceneMap.end(), "GLWorldScene::moleculeInserted() - molecule's id " +toString(board->getMoleculeIdToIndex(_id))+" is unknown."); GLMoleculeObject_molecule *molObject = iter->second; molObject->setVisible(_visible); emit changed(); emit changeOccured(); } /** This converts safely index into a GLMoleculeObject_molecule. * * \param _MoleculesinSceneMap all present molecules * \param _molid index to look for * \return MolObject or NULL when not found */ GLMoleculeObject_molecule *GLWorldScene::getMoleculeObject( const ObservedValue_Index_t _molid) const { const MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(_molid); if (moliter != MoleculesinSceneMap.end()) return moliter->second; else return NULL; } /** Changes the parent of an object in the scene. * * \param _id index of the object whose parent to change * \param _ob new parent */ void GLWorldScene::reparentAtom() { boost::recursive_mutex::scoped_lock lock(Atom_mutex); QObject * origin = sender(); if (origin == NULL) { ELOG(1, "Got reparentAtom() with sender being NULL."); return; } ObservedAtoms_t::const_iterator iter = ObservedAtoms.find(origin); ASSERT( iter != ObservedAtoms.end(), "GLWorldScene::reparentAtom() - atom's "+toString(origin)+" is no longer stored?"); QtObservedAtom::ptr walker = iter->second; const ObservedValue_Index_t walkerid = walker->getIndex(); LOG(4, "DEBUG: GLWorldScene: Received signal moleculeChanged for atom "+toString(walkerid)+"."); AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(walkerid); ASSERT( parentiter != AtomNodeParentMap.left.end(), "GLWorldScene::reparentAtom() - could not find object to id "+toString(walkerid)); // change parent entry AtomNodeParentMap.left.erase(parentiter); if (walker->getMoleculeRef() != NULL) AtomNodeParentMap.left.insert( std::make_pair(walkerid, walker->getMoleculeRef()->getIndex()) ); else AtomNodeParentMap.left.insert( std::make_pair(walkerid, (ObservedValue_Index_t)NULL) ); parentiter = AtomNodeParentMap.left.find(walkerid); const AtomNodeMap::iterator atomiter = AtomsinSceneMap.find(walkerid); if (atomiter != AtomsinSceneMap.end()) resetParent(atomiter->second, getMoleculeObject(parentiter->second)); // else atom does not yet exist // check whether node is still shown, otherwise remove completely checkAndRemoveAtom( walkerid ); } /** Changes the parent of an left-side bond in the scene. * */ void GLWorldScene::reparentBondLeft() { boost::recursive_mutex::scoped_lock lock(Bond_mutex); QObject * origin = sender(); if (origin == NULL) { ELOG(1, "Got reparentBondLeft() with sender being NULL."); return; } ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin); ASSERT( iter != ObservedBonds.end(), "GLWorldScene::reparentBondLeft() - bond "+toString(origin)+" is no longer stored?"); QtObservedBond::ptr bond = iter->second; LOG(3, "INFO: GLWorldScene::reparentBondLeft() - Reparenting left side of bond " << bond->getBondIndex() << "."); reparentBond(bond, bond->getLeftAtom(), GLMoleculeObject_bond::left); // check whether node is still shown, otherwise remove completely checkAndRemoveBond( bond->getIndex() ); } /** Changes the parent of an right-side bond in the scene. * */ void GLWorldScene::reparentBondRight() { boost::recursive_mutex::scoped_lock lock(Bond_mutex); QObject * origin = sender(); if (origin == NULL) { ELOG(1, "Got reparentBondRight() with sender being NULL."); return; } ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin); ASSERT( iter != ObservedBonds.end(), "GLWorldScene::reparentBondRight() - bond "+toString(origin)+" is no longer stored?"); QtObservedBond::ptr bond = iter->second; LOG(3, "INFO: GLWorldScene::reparentBondRight() - Reparenting right side of bond " << bond->getBondIndex() << "."); reparentBond(bond, bond->getRightAtom(), GLMoleculeObject_bond::right); // check whether node is still shown, otherwise remove completely checkAndRemoveBond( bond->getIndex() ); } GLMoleculeObject_bond *GLWorldScene::getBondInScene( const ObservedValue_Index_t _bondid, GLMoleculeObject_bond::SideOfBond _side) const { std::pair iters = BondsinSceneMap.equal_range(_bondid); ASSERT( std::distance(iters.first, iters.second) >= 1, "GLWorldScene::getBondInScene() - not at least one bond of id " +toString(_bondid)+" present in scene."); for (GLWorldScene::BondNodeMap::const_iterator bonditer = iters.first; bonditer != iters.second; ++bonditer) { if (bonditer->second->BondSide == _side) return bonditer->second; } return NULL; } /** Changes the parent of an object in the scene. * * \param _atom atom of bond whose molecule we are associated to * \param _side side of bond */ void GLWorldScene::reparentBond( const QtObservedBond::ptr _bond, const QtObservedAtom::ptr _atom, const GLMoleculeObject_bond::SideOfBond _side) { boost::recursive_mutex::scoped_lock lock(Bond_mutex); const size_t dim = (_side == GLMoleculeObject_bond::left) ? 0 : 1; const ObservedValue_Index_t bondid = _bond->getIndex(); BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[dim].left.find(bondid); ASSERT( parentiter != BondNodeParentMaps[dim].left.end(), "GLWorldScene::reparentBond() - could not find object to id "+toString(bondid)); // change parent entry BondNodeParentMaps[dim].left.erase(bondid); if ((_atom != NULL) && (_atom->getMoleculeRef() != NULL)) BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, _atom->getMoleculeRef()->getIndex())); else BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, (ObservedValue_Index_t)NULL) ); parentiter = BondNodeParentMaps[dim].left.find(bondid); LOG(3, "INFO: GLWorldScene::reparentBond() - Reparented bond " << _bond->getBondIndex() << " to " << parentiter->second); // reset parent resetParent(getBondInScene(bondid, _side), getMoleculeObject(parentiter->second)); } /** Resets the parent of an GLMoleculeObject. * * \param _obj object to reparent * \param _molid index of parent molecule */ void GLWorldScene::resetParent( GLMoleculeObject *_obj, GLMoleculeObject_molecule *_molobj) { if (_obj != NULL) { QObject *parent = this; if (_molobj != NULL) parent = _molobj; // else: molecule does not yet exist: is done when molecule is instantiated LOG(5, "DEBUG: Resetting parent of " << _obj << " to " << parent); _obj->setParent(parent); ASSERT( _obj->parent() == parent, "GLWorldScene::resetParent() - new parent "+toString(parent)+" was not set."); } else ELOG(1, "Object to reparent was NULL."); // else object does not yet exist } /** Adds a shape to the scene. * */ void GLWorldScene::addShape(const std::string &_name) { Shape * const shape = ShapeRegistry::getInstance().getByName(_name); if (shape != NULL) { GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(*shape, this); ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name); ASSERT(iter == ShapesinSceneMap.end(), "GLWorldScene::addShape() - same shape "+_name+" added again."); ShapesinSceneMap.insert( make_pair(_name, shapeObject) ); } else ELOG(2, "GLWorldScene::addShape() - shape disappeared before we could draw it."); emit changed(); } void GLWorldScene::removeShape(const std::string &_name) { ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name); ASSERT(iter != ShapesinSceneMap.end(), "GLWorldScene::removeShape() - shape "+_name+" not in scene."); ShapesinSceneMap.erase(iter); delete(iter->second); emit changed(); } void GLWorldScene::updateSelectedShapes() { foreach (QObject *obj, children()) { GLMoleculeObject_shape *shapeobj = qobject_cast(obj); if (shapeobj){ shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape())); } } emit changed(); } void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const { // Initialize all of the mesh objects that we have as children. foreach (QObject *obj, children()) { GLMoleculeObject *meshobj = qobject_cast(obj); if (meshobj) meshobj->initialize(view, painter); } } void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const { // Draw all of the mesh objects that we have as children. foreach (QObject *obj, children()) { GLMoleculeObject *meshobj = qobject_cast(obj); if (meshobj) meshobj->draw(painter, cameraPlane); } } void GLWorldScene::setSelectionMode(SelectionModeType mode) { selectionMode = mode; // TODO send update to toolbar } void GLWorldScene::setSelectionModeAtom() { setSelectionMode(SelectAtom); } void GLWorldScene::setSelectionModeMolecule() { setSelectionMode(SelectMolecule); }