/* * 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. */ /* * GLMoleculeObject_bond.cpp * * Created on: Aug 17, 2011 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "GLMoleculeObject_bond.hpp" #include #include #include "CodePatterns/MemDebug.hpp" #include #include "CodePatterns/Assert.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Observer/Notification.hpp" #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "Element/element.hpp" #include "Helpers/defs.hpp" #include "LinearAlgebra/Line.hpp" #include "LinearAlgebra/Vector.hpp" GLMoleculeObject_bond::GLMoleculeObject_bond(QGLSceneNode *mesh, QObject *parent, const bond *bondref, const enum SideOfBond side) : GLMoleculeObject(mesh, parent), Observer(std::string("GLMoleculeObject_bond") +toString(bondref->leftatom->getId()) +std::string("-") +toString(bondref->rightatom->getId())), _bond(bondref), BondSide(side) { // sign on as observer (obtain non-const instance before) _bond->signOn(this, BondObservable::BondRemoved); _bond->leftatom->signOn(this, AtomObservable::PositionChanged); _bond->rightatom->signOn(this, AtomObservable::PositionChanged); size_t elementno = 0; switch (BondSide) { case left: if (_bond->leftatom->getType() != NULL) { elementno = _bond->leftatom->getType()->getAtomicNumber(); } else { // if not element yet set, set to hydrogen elementno = 1; } break; case right: if (_bond->rightatom->getType() != NULL) { elementno = _bond->rightatom->getType()->getAtomicNumber(); } else { // if not element yet set, set to hydrogen elementno = 1; } break; default: ASSERT(0, "GLMoleculeObject_bond::GLMoleculeObject_bond() - side is not a valid argument: "+toString(BondSide)+"."); break; } QGLMaterial *elementmaterial = getMaterial(elementno); setMaterial(elementmaterial); resetPosition(); } GLMoleculeObject_bond::~GLMoleculeObject_bond() { // sign on as observer (obtain non-const instance before) if (_bond){ _bond->signOff(this, BondObservable::BondRemoved); _bond->leftatom->signOff(this, AtomObservable::PositionChanged); _bond->rightatom->signOff(this, AtomObservable::PositionChanged); LOG(2, "INFO: Destroying GLMoleculeObject_bond to bond " << *_bond << " and side " << BondSide << "."); }else{ LOG(2, "INFO: Destroying GLMoleculeObject_bond (bond already killed)."); } } void GLMoleculeObject_bond::update(Observable *publisher) { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(this) << " from bond " << *_bond << "."; #endif } void GLMoleculeObject_bond::subjectKilled(Observable *publisher) { LOG(2, "INFO: Received subjectKilled from " << *_bond << "."); switch (BondSide) { case left: emit BondRemoved(_bond->leftatom->getId(), _bond->rightatom->getId()); break; case right: emit BondRemoved(_bond->rightatom->getId(), _bond->leftatom->getId()); break; default: ASSERT(0, "GLMoleculeObject_bond::subjectKilled() - side is not a valid argument: "+toString(BondSide)+"."); break; } // Don't let the destructor automatically sign off from a dead bond! _bond->leftatom->signOff(this, AtomObservable::PositionChanged); _bond->rightatom->signOff(this, AtomObservable::PositionChanged); _bond = NULL; delete this; } void GLMoleculeObject_bond::recieveNotification(Observable *publisher, Notification_ptr notification) { #ifdef LOG_OBSERVER observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(this) << " received notification from bond " << *_bond << " for channel " << notification->getChannelNo() << "."; #endif if (publisher == dynamic_cast(_bond)){ // from the bond switch (notification->getChannelNo()) { case BondObservable::BondRemoved: LOG(2, "INFO: Received notification of BondRemoved from " << *_bond << "."); switch (BondSide) { case left: emit BondRemoved(_bond->leftatom->getId(), _bond->rightatom->getId()); break; case right: emit BondRemoved(_bond->rightatom->getId(), _bond->leftatom->getId()); break; default: ASSERT(0, "GLMoleculeObject_bond::recieveNotification() - side is not a valid argument: "+toString(BondSide)+"."); break; } // Don't let the destructor automatically sign off from a dead bond! _bond->leftatom->signOff(this, AtomObservable::PositionChanged); _bond->rightatom->signOff(this, AtomObservable::PositionChanged); _bond = NULL; delete this; break; default: break; } }else{ // from an atom switch (notification->getChannelNo()) { case AtomObservable::PositionChanged: LOG(2, "INFO: Received notification of PositionChanged."); resetPosition(); emit changed(); } } } void GLMoleculeObject_bond::resetPosition() { Vector Position; Vector OtherPosition; switch (BondSide) { case left: Position = _bond->leftatom->getPosition(); OtherPosition = _bond->rightatom->getPosition(); break; case right: Position = _bond->rightatom->getPosition(); OtherPosition = _bond->leftatom->getPosition(); break; default: ASSERT(0, "GLMoleculeObject_bond::resetPosition() - side is not a valid argument: "+toString(BondSide)+"."); break; } const double distance = Position.distance(OtherPosition)/2.; setScaleZ(distance); // calculate position Vector Z(0.,0.,1.); Vector zeroVec(0.,0.,0.); Vector a,b; Vector OtherAxis; double alpha; a = Position - OtherPosition; // construct rotation axis b = a; b.VectorProduct(Z); Line axis(zeroVec, b); // calculate rotation angle alpha = a.Angle(Z); // construct other axis to check right-hand rule OtherAxis = b; OtherAxis.VectorProduct(Z); // assure right-hand rule for the rotation if (a.ScalarProduct(OtherAxis) < MYEPSILON) alpha = M_PI-alpha; // check Vector a_rotated = axis.rotateVector(a, alpha); LOG(3, "INFO: Created cylinder from "// << Position << " to " << OtherPosition << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively."); // set position setPosition(QVector3D(Position[0], Position[1], Position[2])); setRotationVector(QVector3D(b[0], b[1], b[2])); setRotationAngle(alpha/M_PI*180.); }