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