/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * 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 "GLMoleculeObject.hpp" #include "GLMoleculeObject_atom.hpp" #include "GLMoleculeObject_bond.hpp" #include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Log.hpp" #include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp" #include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp" #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "Descriptors/AtomIdDescriptor.hpp" #include "Helpers/helpers.hpp" #include "molecule.hpp" #include "World.hpp" using namespace MoleCuilder; GLWorldScene::GLWorldScene(QObject *parent) : QObject(parent) { init(); //changeMaterials(false); } GLWorldScene::~GLWorldScene() { // remove all elements GLMoleculeObject::cleanMaterialMap(); } /** Initialise the WorldScene with molecules and atoms from World. * */ void GLWorldScene::init() { const std::vector &molecules = World::getInstance().getAllMolecules(); if (molecules.size() > 0) { for (std::vector::const_iterator Runner = molecules.begin(); Runner != molecules.end(); Runner++) { // create molecule for (molecule::const_iterator atomiter = (*Runner)->begin(); atomiter != (*Runner)->end(); ++atomiter) { // create atom objects in scene atomInserted(*atomiter); // create bond objects in scene bondsChanged(*atomiter); } } } } /** Adds an atom to the scene. * * @param _atom atom to add */ void GLWorldScene::atomInserted(const atom *_atom) { LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "+toString(_atom->getId())+"."); GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(this, _atom); AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atom->getId()); ASSERT(iter == AtomsinSceneMap.end(), "GLWorldScene::atomAdded() - same atom "+_atom->getName()+" added again."); AtomsinSceneMap.insert( make_pair(_atom->getId(), atomObject) ); connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(atomClicked(atomId_t))); connect (atomObject, SIGNAL(hoverChanged()), this, SIGNAL(changed())); connect (atomObject, SIGNAL(BondsChanged(const atom *)), this, SLOT(bondsChanged(const atom *))); bondsChanged(_atom); emit changeOccured(); } /** Removes an atom from the scene. * * @param _atom atom to remove */ void GLWorldScene::atomRemoved(const atom *_atom) { LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atom->getId())+"."); // remove all its bonds const BondList& bondlist = _atom->getListOfBonds(); for (BondList::const_iterator iter = bondlist.begin(); iter != bondlist.end(); ++iter) { bondRemoved((*iter)->leftatom->getId(), (*iter)->rightatom->getId()); bondRemoved((*iter)->rightatom->getId(), (*iter)->leftatom->getId()); } // remove atoms AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atom->getId()); ASSERT(iter != AtomsinSceneMap.end(), "GLWorldScene::atomRemoved() - atom "+_atom->getName()+" not on display."); GLMoleculeObject_atom *atomObject = iter->second; atomObject->disconnect(); AtomsinSceneMap.erase(iter); delete atomObject; emit changeOccured(); } /** Updates the bond structure of the signaled \a _atom. * * @param _atom atom whose bonds changed. */ void GLWorldScene::bondsChanged(const atom *_atom) { const atomId_t id = _atom->getId(); // create list with all present bonds std::set< atomId_t > presentBonds; std::pair< BondIdsMap::const_iterator, BondIdsMap::const_iterator> range = BondIdsinSceneMap.equal_range( id ); for (BondIdsMap::const_iterator iter = range.first; iter != range.second; ++iter) { const atomId_t otherid = iter->second; #ifndef NDEBUG std::set< atomId_t >::const_iterator iter = presentBonds.find(otherid); ASSERT(iter == presentBonds.end(), "GLWorldScene::BondsChanged() - bond id "+toString(otherid)+" for atom " +toString(id)+" present twice."); #endif presentBonds.insert( otherid ); } LOG(3, "INFO: We have the following bonds: "+toString(presentBonds)+"."); // search for added bonds const BondList &bondlist = _atom->getListOfBonds(); for (BondList::const_iterator bonditer = bondlist.begin(); bonditer != bondlist.end(); ++bonditer) { const bond *_bond = *bonditer; const atomId_t otherid = _bond->GetOtherAtom(_atom)->getId(); const BondIds ids = std::make_pair( id, otherid ); BondNodeMap::const_iterator iter = BondsinSceneMap.find(ids); if (iter != BondsinSceneMap.end()) { // bond is already present std::set< atomId_t >::const_iterator iter = presentBonds.find(otherid); ASSERT(iter != presentBonds.end(), "GLWorldScene::BondsChanged() - other id "+toString(otherid)+" for atom " +toString(_atom->getId())+" not present in BondIdsinSceneMap."); presentBonds.erase(otherid); LOG(0, "Removing "+toString(otherid)+" from presentBonds."); } else { // insert new bond bondInserted(_bond); } } if (!presentBonds.empty()) ELOG(2, "The following bonds should not be present: "+toString(presentBonds)+"."); // remove all still presentBonds for (std::set< atomId_t >::iterator iter = presentBonds.begin(); !presentBonds.empty(); iter = presentBonds.begin()) { bondRemoved( id, *iter ); } } /** Adds a bond to the scene. * * @param _bond bond to add */ void GLWorldScene::bondInserted(const bond *_bond) { LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+"."); const double distance = _bond->leftatom->getPosition().distance(_bond->rightatom->getPosition())/2.; { // left bond const BondIds Leftids( make_pair(_bond->leftatom->getId(), _bond->rightatom->getId()) ); BondNodeMap::iterator iter = BondsinSceneMap.find(Leftids); ASSERT(iter == BondsinSceneMap.end(), "GLWorldScene::bondAdded() - same left-sided bond "+toString(*_bond)+" added again."); GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(this, _bond, distance, GLMoleculeObject_bond::left); BondsinSceneMap.insert( make_pair(Leftids, bondObject) ); BondIdsinSceneMap.insert( Leftids ); } { // right bond const BondIds Rightids( make_pair(_bond->rightatom->getId(), _bond->leftatom->getId()) ); BondNodeMap::iterator iter = BondsinSceneMap.find(Rightids); ASSERT(iter == BondsinSceneMap.end(), "GLWorldScene::bondAdded() - same right-sided bond "+toString(*_bond)+" added again."); GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(this, _bond, distance, GLMoleculeObject_bond::right); BondsinSceneMap.insert( make_pair(Rightids, bondObject) ); BondIdsinSceneMap.insert( Rightids ); } emit changeOccured(); } /** Removes a bond from the scene. * * @param _bond bond to remove */ void GLWorldScene::bondRemoved(const atomId_t leftnr, const atomId_t rightnr) { LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(leftnr)+"."); { // left bond const BondIds Leftids( make_pair(leftnr, rightnr) ); BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids ); ASSERT(leftiter != BondsinSceneMap.end(), "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-" +toString(rightnr)+" not on display."); GLMoleculeObject_bond *bondObject = leftiter->second; BondsinSceneMap.erase(leftiter); delete bondObject; } // remove from bond ids std::pair leftrange = BondIdsinSceneMap.equal_range(leftnr); BondIdsMap::iterator iter; for (iter = leftrange.first; iter != leftrange.second; ++iter) { if (iter->second == rightnr) { BondIdsinSceneMap.erase(iter); break; } } ASSERT(iter != leftrange.second, "GLWorldScene::bondRemoved() - could not find (" +toString(leftnr)+"-"+toString(rightnr)+" in BondIdsinSceneMap."); emit changeOccured(); } 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 { // 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); } } void GLWorldScene::atomClicked(atomId_t no) { LOG(3, "INFO: GLWorldScene - atom " << no << " has been clicked."); const atom *Walker = World::getInstance().getAtom(AtomById(no)); if (!World::getInstance().isSelected(Walker)) SelectionAtomById(no); else SelectionNotAtomById(no); emit clicked(no); }