/* * 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 #include #include #include #include #include "GLMoleculeObject.hpp" #include "GLMoleculeObject_atom.hpp" #include "GLMoleculeObject_bond.hpp" #include "GLMoleculeObject_molecule.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" #include using namespace MoleCuilder; std::ostream &operator<<(std::ostream &ost, const GLWorldScene::BondIds &t) { ost << t.first << "," << t.second; return ost; } GLWorldScene::GLWorldScene(QObject *parent) : QObject(parent) { QGLBuilder builder0; meshEmpty = builder0.finalizedSceneNode(); QGLBuilder builder1; builder1 << QGLSphere(2.0, 5); meshSphereHi = builder1.finalizedSceneNode(); QGLBuilder builder2; builder2 << QGLSphere(2.0, 1); meshSphereLo = builder2.finalizedSceneNode(); QGLBuilder builder3; builder3 << QGLCylinder(.25,.25,1.0,16); meshCylinderHi = builder3.finalizedSceneNode(); QGLBuilder builder4; builder4 << QGLCylinder(.25,.25,1.0,16); meshCylinderLo = builder4.finalizedSceneNode(); meshSphereHi->setOption(QGLSceneNode::CullBoundingBox, true); meshSphereLo->setOption(QGLSceneNode::CullBoundingBox, true); meshCylinderHi->setOption(QGLSceneNode::CullBoundingBox, true); meshCylinderLo->setOption(QGLSceneNode::CullBoundingBox, true); init(); } 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++) { for (molecule::const_iterator atomiter = (*Runner)->begin(); atomiter != (*Runner)->end(); ++atomiter) { // create atom objects in scene atomInserted(*atomiter); // create bond objects in scene const BondList &bondlist = (*atomiter)->getListOfBonds(); for (BondList::const_iterator bonditer = bondlist.begin(); bonditer != bondlist.end(); ++bonditer) { const bond *_bond = *bonditer; const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == *atomiter) ? GLMoleculeObject_bond::left : GLMoleculeObject_bond::right; bondInserted(_bond, side); } } } } } /** 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(meshSphereHi, 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(changed()), this, SIGNAL(changed())); connect (atomObject, SIGNAL(hoverChanged()), this, SIGNAL(changed())); connect (atomObject, SIGNAL(selectionChanged()), this, SIGNAL(changed())); connect (atomObject, SIGNAL(BondsInserted(const bond *, const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const bond *, const GLMoleculeObject_bond::SideOfBond))); //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())+"."); // bonds are removed by signal coming from ~bond // 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(); } /** .... * */ void GLWorldScene::worldSelectionChanged() { LOG(3, "INFO: GLWorldScene: Received signal selectionChanged."); const std::vector &molecules = World::getInstance().getAllMolecules(); if (molecules.size() > 0) { for (std::vector::const_iterator Runner = molecules.begin(); Runner != molecules.end(); Runner++) { MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find((*Runner)->getId()); bool isSelected = World::getInstance().isSelected(*Runner); // molecule selected but not in scene? if (isSelected && (iter == MoleculesinSceneMap.end())){ // -> create new mesh GLMoleculeObject_molecule *molObject = new GLMoleculeObject_molecule(meshEmpty, this, *Runner); MoleculesinSceneMap.insert( make_pair((*Runner)->getId(), molObject) ); connect (molObject, SIGNAL(changed()), this, SIGNAL(changed())); connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed())); connect (molObject, SIGNAL(selectionChanged()), this, SIGNAL(changed())); emit changed(); emit changeOccured(); } // molecule not selected but in scene? if (!isSelected && (iter != MoleculesinSceneMap.end())){ // -> remove from scene moleculeRemoved(*Runner); } } } } /** Removes a molecule from the scene. * * @param _molecule molecule to remove */ void GLWorldScene::moleculeRemoved(const molecule *_molecule) { LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molecule->getId())+"."); MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molecule->getId()); // only remove if the molecule is in the scene // (= is selected) if (iter != MoleculesinSceneMap.end()){ GLMoleculeObject_molecule *molObject = iter->second; molObject->disconnect(); MoleculesinSceneMap.erase(iter); delete molObject; emit changed(); emit changeOccured(); } } /** Adds a bond to the scene. * * @param _bond bond to add * @param side which side of the bond (left or right) */ void GLWorldScene::bondInserted(const bond *_bond, const enum GLMoleculeObject_bond::SideOfBond side) { LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+"."); //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << "."); BondIds ids; switch (side) { case GLMoleculeObject_bond::left: ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId()); break; case GLMoleculeObject_bond::right: ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId()); break; } #ifndef NDEBUG BondNodeMap::iterator iter = BondsinSceneMap.find(ids); ASSERT(iter == BondsinSceneMap.end(), "GLWorldScene::bondAdded() - same left-sided bond "+toString(*_bond)+" added again."); #endif GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(meshCylinderHi, this, _bond, side); connect ( bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)), this, SLOT(bondRemoved(const atomId_t, const atomId_t))); connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed())); BondsinSceneMap.insert( make_pair(ids, bondObject) ); // BondIdsinSceneMap.insert( Leftids ); 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(rightnr)+"."); { // 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; // is done by signal from bond itself //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << "."); } 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); }