/*
* 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_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 "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
#include "CodePatterns/MemDebug.hpp"
#include
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.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"
#include "World.hpp"
GLMoleculeObject_bond::GLMoleculeObject_bond(
QGLSceneNode *mesh[],
QObject *parent,
QtObservedBond::ptr &_ObservedBond,
const enum SideOfBond side) :
GLMoleculeObject(mesh, parent),
BondSide(side),
ObservedBond(_ObservedBond)
{
resetElement();
resetPosition();
resetWidth();
// connect to observed bond's signals
connect(_ObservedBond.get(), SIGNAL(degreeChanged()), this, SLOT(resetWidth()));
if (side == left)
connect(_ObservedBond.get(), SIGNAL(leftAtomElementChanged()), this, SLOT(resetElement()));
else
connect(_ObservedBond.get(), SIGNAL(rightAtomElementChanged()), this, SLOT(resetElement()));
connect(_ObservedBond.get(), SIGNAL(leftAtomPositionChanged()), this, SLOT(resetPosition()));
connect(_ObservedBond.get(), SIGNAL(rightAtomPositionChanged()), this, SLOT(resetPosition()));
}
static const atomicNumber_t& getElement(
const QtObservedBond::ptr &_ObservedBond,
const enum GLMoleculeObject_bond::SideOfBond _side)
{
if (_side == GLMoleculeObject_bond::left)
return _ObservedBond->getLeftAtomElement();
else
return _ObservedBond->getRightAtomElement();
}
static const Vector& getPosition(
const QtObservedBond::ptr &_ObservedBond,
const enum GLMoleculeObject_bond::SideOfBond _side)
{
if (_side == GLMoleculeObject_bond::left)
return _ObservedBond->getLeftAtomPosition();
else
return _ObservedBond->getRightAtomPosition();
}
static const Vector& getOtherPosition(
const QtObservedBond::ptr &_ObservedBond,
const enum GLMoleculeObject_bond::SideOfBond _side)
{
if (_side == GLMoleculeObject_bond::left)
return _ObservedBond->getRightAtomPosition();
else
return _ObservedBond->getLeftAtomPosition();
}
GLMoleculeObject_bond::~GLMoleculeObject_bond()
{
LOG(4, "DEBUG: Destroying GLMoleculeObject_bond to bond [" <<
ObservedBond->getBondIndex() << "] and side " << BondSide << ".");
// signOff() if not already done
}
void GLMoleculeObject_bond::resetElement()
{
const atomicNumber_t& elementno = getElement(ObservedBond, BondSide);
QGLMaterial *elementmaterial = getMaterial(elementno);
setMaterial(elementmaterial);
}
void GLMoleculeObject_bond::resetWidth()
{
const double factor = 1.0f+.5f*(ObservedBond->getBondDegree()-1);
LOG(4, "DEBUG: GLMoleculeObject_bond::resetWidth() - setting bond's width to " << factor << ".");
setScaleX(factor);
setScaleY(factor);
emit changed();
}
void GLMoleculeObject_bond::resetPosition()
{
const Vector& Position = getPosition(ObservedBond, BondSide);
const Vector& OtherPosition = getOtherPosition(ObservedBond, BondSide);
const double distance =
Position.distance(OtherPosition)/2.;
setScaleZ(distance);
// calculate position
Vector Z(unitVec[2]); // cylinder are initially aligned along the Z axis
Vector zeroVec(0.,0.,0.);
Vector a,b;
Vector OtherAxis;
double alpha;
a = OtherPosition - Position;
// 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(4, "DEBUG: Created cylinder from "// << Position << " to " << OtherPosition
<< a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively.");
// set position (cylinder offset is in its barymetric center)
Vector OneFourth(OtherPosition - 0.75 * a);
setPosition(QVector3D(OneFourth[0], OneFourth[1], OneFourth[2]));
setRotationVector(QVector3D(b[0], b[1], b[2]));
setRotationAngle(alpha/M_PI*180.);
emit changed();
}