/*
* 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 .
*/
/*
* GLMoleculeObject_atom.cpp
*
* Created on: Aug 17, 2011
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "GLMoleculeObject_atom.hpp"
#include
#include "CodePatterns/MemDebug.hpp"
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include "CodePatterns/Observer/Notification.hpp"
#include "Atom/atom.hpp"
#include "Bond/bond.hpp"
#include "Descriptors/AtomIdDescriptor.hpp"
#include "Element/element.hpp"
#include "LinearAlgebra/Vector.hpp"
#include "GLMoleculeObject_bond.hpp"
#include "World.hpp"
#include "WorldTime.hpp"
GLMoleculeObject_atom::GLMoleculeObject_atom(QGLSceneNode *mesh[], QObject *parent, const atom *atomref) :
GLMoleculeObject(mesh, parent),
Observer(std::string("GLMoleculeObject_atom")+toString(atomref->getId())),
_atom(atomref)
{
// sign on as observer (obtain non-const instance before)
atomref->signOn(this, AtomObservable::IndexChanged);
atomref->signOn(this, AtomObservable::PositionChanged);
atomref->signOn(this, AtomObservable::ElementChanged);
atomref->signOn(this, AtomObservable::BondsAdded);
World::getInstance().signOn(this, World::SelectionChanged);
WorldTime::getInstance().signOn(this, WorldTime::TimeChanged);
// set the object's id
resetProperties();
LOG(2, "INFO: Created sphere for atom " << _atom->getId() << ".");
connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
}
GLMoleculeObject_atom::~GLMoleculeObject_atom()
{
if (_atom){
_atom->signOff(this, AtomObservable::IndexChanged);
_atom->signOff(this, AtomObservable::PositionChanged);
_atom->signOff(this, AtomObservable::ElementChanged);
_atom->signOff(this, AtomObservable::BondsAdded);
}
World::getInstance().signOff(this, World::SelectionChanged);
WorldTime::getInstance().signOff(this, WorldTime::TimeChanged);
}
void GLMoleculeObject_atom::update(Observable *publisher)
{
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(static_cast(this)) << " from atom "+toString(_atom->getId())+".";
#endif
resetProperties();
}
void GLMoleculeObject_atom::resetPosition()
{
const Vector Position = _atom->getPosition();
LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new position is "+toString(Position)+".");
setPosition(QVector3D(Position[0], Position[1], Position[2]));
}
void GLMoleculeObject_atom::resetElement()
{
size_t elementno = 0;
if (_atom->getType() != NULL) {
elementno = _atom->getType()->getAtomicNumber();
} else { // if no element yet, set to hydrogen
elementno = 1;
}
LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new element number is "+toString(elementno)+".");
// set materials
QGLMaterial *elementmaterial = getMaterial(elementno);
ASSERT(elementmaterial != NULL,
"GLMoleculeObject_atom::GLMoleculeObject_atom() - QGLMaterial ref from getter function is NULL.");
setMaterial(elementmaterial);
// set scale
double radius = 0.;
if (_atom->getType() != NULL) {
radius = _atom->getType()->getVanDerWaalsRadius();
} else {
radius = 0.5;
}
setScale( radius / 4. );
}
void GLMoleculeObject_atom::resetIndex()
{
int oldId = objectId();
const size_t atomno = _atom->getId();
LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(atomno)+".");
setObjectId(atomno);
emit indexChanged(this, oldId, atomno);
}
void GLMoleculeObject_atom::resetProperties()
{
// set position
resetPosition();
// set element
resetElement();
// set the object's id
resetIndex();
// selected?
setSelected(World::getInstance().isSelected(_atom));
}
void GLMoleculeObject_atom::subjectKilled(Observable *publisher)
{
_atom = NULL;
}
void GLMoleculeObject_atom::recieveNotification(Observable *publisher, Notification_ptr notification)
{
if (publisher == dynamic_cast(_atom)){
// notofication from atom
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast(this))
<< " received notification from atom " << _atom->getId() << " for channel "
<< notification->getChannelNo() << ".";
#endif
switch (notification->getChannelNo()) {
case AtomObservable::ElementChanged:
resetElement();
emit changed();
break;
case AtomObservable::IndexChanged:
resetIndex();
break;
case AtomObservable::PositionChanged:
resetPosition();
emit changed();
break;
case AtomObservable::BondsAdded:
{
ASSERT(!_atom->getListOfBonds().empty(),
"GLMoleculeObject_atom::recieveNotification() - received BondsAdded but ListOfBonds is empty.");
const bond::ptr _bond = *(_atom->getListOfBonds().rbegin());
const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ?
GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
emit BondsInserted(_bond, side);
break;
}
default:
//setProperties();
break;
}
}else if (static_cast(publisher) == World::getPointer()) {
// notification from world
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast(this))
<< " received notification from world for channel "
<< notification->getChannelNo() << ".";
#endif
switch (notification->getChannelNo()) {
case World::SelectionChanged:
setSelected(World::getInstance().isSelected(_atom));
break;
default:
break;
}
} else {
// notification from world
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast(this))
<< " received notification from Worldtime for channel "
<< notification->getChannelNo() << ".";
#endif
switch (notification->getChannelNo()) {
case WorldTime::TimeChanged:
resetPosition();
emit changed();
break;
default:
break;
}
}
}
void GLMoleculeObject_atom::wasClicked()
{
LOG(4, "INFO: GLMoleculeObject_atom: atom " << _atom->getId() << " has been clicked");
emit clicked(_atom->getId());
}