/* * 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 #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "Element/element.hpp" #include "Element/periodentafel.hpp" #include "LinearAlgebra/Line.hpp" #include "LinearAlgebra/Vector.hpp" #include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_bond.hpp" #include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp" #include "World.hpp" GLMoleculeObject_atom::GLMoleculeObject_atom( QGLSceneNode *mesh[], QGLSceneNode *mesharrow[], QObject *parent, QtObservedAtom::ptr &_ObservedAtom) : GLMoleculeObject(mesh, parent), GLMoleculeObjectVelocity(mesharrow, this), GLMoleculeObjectForce(mesharrow, this), ObservedAtom(_ObservedAtom) { init(ObservedAtom->getAtomIndex()); } void GLMoleculeObject_atom::init(const atomId_t _id) { setObjectId(_id); resetPosition(); resetVelocity(); resetForce(); resetElement(); GLMoleculeObjectVelocity.setMaterial(GLMoleculeObject::m_velocityMaterial); GLMoleculeObjectForce.setMaterial(GLMoleculeObject::m_forceMaterial); m_selected = ObservedAtom->getAtomSelected(); connect( this, SIGNAL(clicked()), this, SLOT(wasClicked())); connect( ObservedAtom.get(), SIGNAL(indexChanged()), this, SLOT(resetIndex())); connect( ObservedAtom.get(), SIGNAL(elementChanged()), this, SLOT(resetElement())); connect( ObservedAtom.get(), SIGNAL(positionChanged()), this, SLOT(resetPosition())); connect( ObservedAtom.get(), SIGNAL(velocityChanged()), this, SLOT(resetVelocity())); connect( ObservedAtom.get(), SIGNAL(forceChanged()), this, SLOT(resetForce())); connect( ObservedAtom.get(), SIGNAL(selectedChanged()), this, SLOT(resetSelected())); } GLMoleculeObject_atom::~GLMoleculeObject_atom() {} void GLMoleculeObject_atom::resetIndex() { const atomId_t newId = ObservedAtom->getAtomIndex(); const size_t oldId = objectId(); ASSERT( newId != oldId, "GLMoleculeObject_atom::updateIndex() - index "+toString(newId)+" did not change."); LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(newId)+"."); setObjectId(newId); emit indexChanged(this, oldId, newId); } static void setArrow( const Vector &_position, const Vector &_arrow, const double _offset, GLMoleculeObject &_obj) { // set position (cylinder offset is in its barymetric center) Vector OneFourth(_position + (_offset/_arrow.Norm()+.75) * _arrow); _obj.setPosition(QVector3D(OneFourth[0], OneFourth[1], OneFourth[2])); } void GLMoleculeObject_atom::resetPosition() { const Vector Position = ObservedAtom->getAtomPosition(); LOG(4, "INFO: GLMoleculeObject_atom::resetPosition() - new position is "+toString(Position)+"."); setPosition(QVector3D(Position[0], Position[1], Position[2])); setArrow(Position, 10.*ObservedAtom->getAtomVelocity(), scaleX(), GLMoleculeObjectVelocity); setArrow(Position, 10.*ObservedAtom->getAtomForce(), scaleX(), GLMoleculeObjectForce); } static void alignArrow( const Vector &_arrow, GLMoleculeObject &_obj) { if (_arrow.IsZero()) { _obj.setScaleZ(0.); return; } // calculate position Vector Z(unitVec[2]); // cylinder are initially aligned along the Z axis Vector b; Vector OtherAxis; double alpha; // construct rotation axis b = -1.*_arrow; b.VectorProduct(Z); Line axis(zeroVec, b); // calculate rotation angle alpha = _arrow.Angle(Z); // construct other axis to check right-hand rule OtherAxis = b; OtherAxis.VectorProduct(Z); // assure right-hand rule for the rotation if (_arrow.ScalarProduct(OtherAxis) < MYEPSILON) alpha = M_PI-alpha; // check Vector a_rotated = axis.rotateVector(_arrow, alpha); LOG(5, "DEBUG: Aligning arrow " << _arrow << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << "."); _obj.setScaleZ(10.*_arrow.Norm()); _obj.setRotationVector(QVector3D(b[0], b[1], b[2])); _obj.setRotationAngle(alpha/M_PI*180.); } void GLMoleculeObject_atom::resetVelocity() { const Vector Velocity = ObservedAtom->getAtomVelocity(); LOG(4, "INFO: GLMoleculeObject_atom::resetVelocity() - new velocity is "+toString(Velocity)+"."); alignArrow(Velocity, GLMoleculeObjectVelocity); // GLMoleculeObjectForce.setScaleZ(Velocity.Norm()); } void GLMoleculeObject_atom::resetForce() { const Vector Force = ObservedAtom->getAtomForce(); LOG(4, "INFO: GLMoleculeObject_atom::resetForce() - new force is "+toString(Force)+"."); alignArrow(Force, GLMoleculeObjectForce); // GLMoleculeObjectForce.setScaleZ(Force.Norm()); } void GLMoleculeObject_atom::resetElement() { size_t elementno = 0; const element * const _type = World::getInstance(). getPeriode()->FindElement(ObservedAtom->getAtomElement()); if (_type != NULL) { elementno = _type->getAtomicNumber(); } else { // if no element yet, set to hydrogen elementno = 1; } LOG(4, "INFO: GLMoleculeObject_atom::resetElement() - new element number is "+toString(elementno)+"."); // set materials QGLMaterial *elementmaterial = getMaterial(elementno); ASSERT(elementmaterial != NULL, "GLMoleculeObject_atom::resetElement() - QGLMaterial ref from getter function is NULL."); setMaterial(elementmaterial); // set scale double radius = 0.; if (_type != NULL) { radius = _type->getVanDerWaalsRadius(); } else { radius = 0.5; } setScale( radius / 4. ); } void GLMoleculeObject_atom::resetSelected() { // we ascertain check that selection state changed as the Qt signal might be executed // at a later stage when the state has changed yet again const bool new_selected = ObservedAtom->getAtomSelected(); m_selected = new_selected; emit changed(); } void GLMoleculeObject_atom::draw(QGLPainter *painter, const QVector4D &cameraPlane) { // call old hook to do the actual paining GLMoleculeObject::draw(painter, cameraPlane); GLMoleculeObjectVelocity.draw(painter, cameraPlane); GLMoleculeObjectForce.draw(painter, cameraPlane); } void GLMoleculeObject_atom::wasClicked() { LOG(4, "INFO: GLMoleculeObject_atom: atom " << ObservedAtom->getAtomIndex() << " has been clicked"); emit clicked(ObservedAtom->getAtomIndex()); }