/* * 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; GLWorldScene::GLWorldScene( QtObservedInstanceBoard * _board, QObject *parent) : QObject(parent), 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(moleculeInserted(QtObservedMolecule::ptr))); connect(board, SIGNAL(moleculeRemoved(ObservedValue_Index_t)), this, SLOT(moleculeRemoved(ObservedValue_Index_t))); connect(board, SIGNAL(atomInserted(QtObservedAtom::ptr)), this, SLOT(atomInserted(QtObservedAtom::ptr))); connect(board, SIGNAL(atomRemoved(ObservedValue_Index_t)), this, SLOT(atomRemoved(ObservedValue_Index_t))); connect(board, SIGNAL(bondInserted(QtObservedBond::ptr)), this, SLOT(bondInserted(QtObservedBond::ptr))); connect(board, SIGNAL(bondRemoved(ObservedValue_Index_t)), this, SLOT(bondRemoved(ObservedValue_Index_t))); // connect(this, SIGNAL(updated()), this, SLOT(update())); } GLWorldScene::~GLWorldScene() { // remove all elements GLMoleculeObject::cleanMaterialMap(); } void GLWorldScene::atomClicked(atomId_t no) { LOG(3, "INFO: GLMoleculeObject_molecule - atom " << no << " has been clicked."); const atom * const Walker = const_cast(World::getInstance()). getAtom(AtomById(no)); ASSERT( Walker != NULL, "GLWorldScene::atomClicked() - 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); } /** Adds an atom to the scene. * * @param _atom atom to add */ void GLWorldScene::atomInserted(QtObservedAtom::ptr _atom) { LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom " << _atom->getAtomIndex()); GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom( GLMoleculeObject::meshSphere, this, /* parent is GLWorldScene */ _atom); ASSERT( atomObject != NULL, "GLWorldScene::atomInserted - could not create atom object for " +toString(_atom->getAtomIndex())); const ObservedValue_Index_t atomid = _atom->getIndex(); AtomNodeMap::iterator iter = AtomsinSceneMap.find(atomid); ASSERT(iter == AtomsinSceneMap.end(), "GLWorldScene::atomInserted - same atom with id " +toString(_atom->getAtomIndex())+" added again."); AtomsinSceneMap.insert( make_pair(atomid, atomObject) ); connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(atomClicked(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(); } /** Removes an atom. * * @param _atomid index of the atom that is removed */ void GLWorldScene::atomRemoved(ObservedValue_Index_t _atomid) { LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atomid)+"."); // bonds are removed by signal coming from ~bond // remove atoms AtomNodeMap::iterator iter = AtomsinSceneMap.find(_atomid); ASSERT(iter != AtomsinSceneMap.end(), "GLWorldScene::atomRemoved() - atom "+toString(_atomid)+" not on display."); GLMoleculeObject_atom *atomObject = iter->second; AtomsinSceneMap.erase(iter); delete atomObject; emit changed(); emit changeOccured(); } /** Adds a bond to the scene. * * @param _bond bond to add */ void GLWorldScene::bondInserted(QtObservedBond::ptr _bond) { static const std::vector< GLMoleculeObject_bond::SideOfBond > bondsides = boost::assign::list_of (GLMoleculeObject_bond::left) (GLMoleculeObject_bond::right); LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bonds " << _bond->getBondIndex()); //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << "."); const ObservedValue_Index_t bondid = _bond->getIndex(); BondNodeMap::iterator iter = BondsinSceneMap.find(bondid); ASSERT( iter == BondsinSceneMap.end(), "GLWorldScene::bondInserted() - bond "+toString(bondid)+" is already known."); for (size_t i=0;i<2;++i) { GLMoleculeObject_bond * bondObject = new GLMoleculeObject_bond(GLMoleculeObject::meshCylinder, this, _bond, bondsides[i]); connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed())); BondsinSceneMap.insert( std::make_pair(bondid, bondObject) ); } emit changed(); emit changeOccured(); } /** Removes a bond. * * @param _bondid id of bond to remove */ void GLWorldScene::bondRemoved(ObservedValue_Index_t _bondid) { LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond to id " << _bondid); // left bond BondNodeMap::iterator iter = BondsinSceneMap.find(_bondid); ASSERT( iter != BondsinSceneMap.end(), "GLWorldScene::bondRemoved() - could not find bond to id "+toString(_bondid)); GLMoleculeObject_bond *bondObject = iter->second; delete bondObject; // is done by signal from bond itself //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << "."); BondsinSceneMap.erase(iter); emit changed(); emit changeOccured(); } void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob) { // 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::moleculeClicked(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::moleculeInserted(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::moleculeInserted() - molecule's id "+toString(_mol->getMolIndex()) +" already present."); // add new object LOG(1, "DEBUG: Adding GLMoleculeObject_molecule to id " << _mol->getMolIndex()); GLMoleculeObject_molecule *molObject = new GLMoleculeObject_molecule( GLMoleculeObject::meshEmpty, this, _mol); ASSERT( molObject != NULL, "GLWorldScene::moleculeInserted - could not create molecule object for " +toString(_mol->getMolIndex())); #ifndef NDEBUG std::pair inserter = #endif MoleculesinSceneMap.insert( make_pair(molid, molObject) ); ASSERT(inserter.second, "GLWorldScene::moleculeInserted() - 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::moleculeRemoved(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::moleculeRemoved() - to be removed molecule "+toString(_molid) +" is already gone."); // check if it's already empty GLMoleculeObject_molecule *molObject = iter->second; 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(); } /** 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); }