/*
* 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());
}