| [907636] | 1 | /* | 
|---|
|  | 2 | * Project: MoleCuilder | 
|---|
|  | 3 | * Description: creates and alters molecular systems | 
|---|
| [0aa122] | 4 | * Copyright (C)  2010-2012 University of Bonn. All rights reserved. | 
|---|
| [5aaa43] | 5 | * Copyright (C)  2013 Frederik Heber. All rights reserved. | 
|---|
| [94d5ac6] | 6 | * | 
|---|
|  | 7 | * | 
|---|
|  | 8 | *   This file is part of MoleCuilder. | 
|---|
|  | 9 | * | 
|---|
|  | 10 | *    MoleCuilder is free software: you can redistribute it and/or modify | 
|---|
|  | 11 | *    it under the terms of the GNU General Public License as published by | 
|---|
|  | 12 | *    the Free Software Foundation, either version 2 of the License, or | 
|---|
|  | 13 | *    (at your option) any later version. | 
|---|
|  | 14 | * | 
|---|
|  | 15 | *    MoleCuilder is distributed in the hope that it will be useful, | 
|---|
|  | 16 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 17 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
|  | 18 | *    GNU General Public License for more details. | 
|---|
|  | 19 | * | 
|---|
|  | 20 | *    You should have received a copy of the GNU General Public License | 
|---|
|  | 21 | *    along with MoleCuilder.  If not, see <http://www.gnu.org/licenses/>. | 
|---|
| [907636] | 22 | */ | 
|---|
|  | 23 |  | 
|---|
|  | 24 | /* | 
|---|
|  | 25 | * GLMoleculeObject_atom.cpp | 
|---|
|  | 26 | * | 
|---|
|  | 27 | *  Created on: Aug 17, 2011 | 
|---|
|  | 28 | *      Author: heber | 
|---|
|  | 29 | */ | 
|---|
|  | 30 |  | 
|---|
|  | 31 | // include config.h | 
|---|
|  | 32 | #ifdef HAVE_CONFIG_H | 
|---|
|  | 33 | #include <config.h> | 
|---|
|  | 34 | #endif | 
|---|
|  | 35 |  | 
|---|
|  | 36 | #include "GLMoleculeObject_atom.hpp" | 
|---|
|  | 37 |  | 
|---|
|  | 38 | #include <Qt3D/qglscenenode.h> | 
|---|
|  | 39 |  | 
|---|
|  | 40 | #include "CodePatterns/MemDebug.hpp" | 
|---|
|  | 41 |  | 
|---|
|  | 42 | #include "CodePatterns/Assert.hpp" | 
|---|
| [7188b1] | 43 | #include "CodePatterns/Log.hpp" | 
|---|
| [02ce36] | 44 | #include "CodePatterns/Observer/Notification.hpp" | 
|---|
| [907636] | 45 |  | 
|---|
| [2ad1ec] | 46 | #include "Atom/atom.hpp" | 
|---|
|  | 47 | #include "Bond/bond.hpp" | 
|---|
| [7188b1] | 48 | #include "Descriptors/AtomIdDescriptor.hpp" | 
|---|
| [3bdb6d] | 49 | #include "Element/element.hpp" | 
|---|
| [907636] | 50 | #include "LinearAlgebra/Vector.hpp" | 
|---|
| [2ad1ec] | 51 | #include "GLMoleculeObject_bond.hpp" | 
|---|
| [7188b1] | 52 | #include "World.hpp" | 
|---|
| [89b992] | 53 | #include "WorldTime.hpp" | 
|---|
| [907636] | 54 |  | 
|---|
| [917659] | 55 | GLMoleculeObject_atom::GLMoleculeObject_atom(QGLSceneNode *mesh[], QObject *parent, const atomId_t _id) : | 
|---|
| [bca99d] | 56 | GLMoleculeObject(mesh, parent), | 
|---|
| [917659] | 57 | Observer(std::string("GLMoleculeObject_atom")+toString(_id)), | 
|---|
| [f115cc] | 58 | atomicid(_id), | 
|---|
|  | 59 | uptodatePosition(false), | 
|---|
|  | 60 | uptodateElement(false) | 
|---|
| [7188b1] | 61 | { | 
|---|
|  | 62 | // sign on as observer (obtain non-const instance before) | 
|---|
| [f01769] | 63 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 64 | getAtom(AtomById(atomicid)); | 
|---|
| [917659] | 65 | if (_atom != NULL) { | 
|---|
|  | 66 | _atom->signOn(this, AtomObservable::IndexChanged); | 
|---|
|  | 67 | _atom->signOn(this, AtomObservable::PositionChanged); | 
|---|
|  | 68 | _atom->signOn(this, AtomObservable::ElementChanged); | 
|---|
|  | 69 | _atom->signOn(this, AtomObservable::BondsAdded); | 
|---|
|  | 70 | } else { | 
|---|
|  | 71 | ELOG(2, "Atom with id "+toString(atomicid)+" is already gone."); | 
|---|
|  | 72 | } | 
|---|
| [d53902] | 73 | World::getInstance().signOn(this, World::SelectionChanged); | 
|---|
| [7188b1] | 74 |  | 
|---|
|  | 75 | // set the object's id | 
|---|
|  | 76 | resetProperties(); | 
|---|
|  | 77 |  | 
|---|
| [917659] | 78 | LOG(2, "INFO: Created sphere for atom " << atomicid << "."); | 
|---|
| [7188b1] | 79 |  | 
|---|
|  | 80 | connect( this, SIGNAL(clicked()), this, SLOT(wasClicked())); | 
|---|
|  | 81 | } | 
|---|
|  | 82 |  | 
|---|
| [9c18e4] | 83 | GLMoleculeObject_atom::~GLMoleculeObject_atom() | 
|---|
|  | 84 | { | 
|---|
| [f01769] | 85 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 86 | getAtom(AtomById(atomicid)); | 
|---|
| [917659] | 87 | if (_atom != NULL){ | 
|---|
| [c736fe] | 88 | _atom->signOff(this, AtomObservable::IndexChanged); | 
|---|
|  | 89 | _atom->signOff(this, AtomObservable::PositionChanged); | 
|---|
|  | 90 | _atom->signOff(this, AtomObservable::ElementChanged); | 
|---|
|  | 91 | _atom->signOff(this, AtomObservable::BondsAdded); | 
|---|
|  | 92 | } | 
|---|
| [d53902] | 93 | World::getInstance().signOff(this, World::SelectionChanged); | 
|---|
| [9c18e4] | 94 | } | 
|---|
|  | 95 |  | 
|---|
| [7188b1] | 96 | void GLMoleculeObject_atom::update(Observable *publisher) | 
|---|
|  | 97 | { | 
|---|
| [57a770] | 98 | #ifdef LOG_OBSERVER | 
|---|
| [917659] | 99 | observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(static_cast<Observer *>(this)) << " from atom "+toString(atomicid)+"."; | 
|---|
| [57a770] | 100 | #endif | 
|---|
| [7188b1] | 101 | resetProperties(); | 
|---|
|  | 102 | } | 
|---|
|  | 103 |  | 
|---|
|  | 104 | void GLMoleculeObject_atom::resetPosition() | 
|---|
| [907636] | 105 | { | 
|---|
| [f01769] | 106 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 107 | getAtom(AtomById(atomicid)); | 
|---|
| [917659] | 108 | if (_atom != NULL) { | 
|---|
|  | 109 | const Vector Position = _atom->getPosition(); | 
|---|
|  | 110 | LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new position is "+toString(Position)+"."); | 
|---|
|  | 111 | setPosition(QVector3D(Position[0], Position[1], Position[2])); | 
|---|
|  | 112 | } else { | 
|---|
|  | 113 | ELOG(2, "Atom with id "+toString(atomicid)+" is already gone."); | 
|---|
|  | 114 | } | 
|---|
| [f115cc] | 115 | uptodatePosition = true; | 
|---|
| [7188b1] | 116 | } | 
|---|
|  | 117 |  | 
|---|
|  | 118 | void GLMoleculeObject_atom::resetElement() | 
|---|
|  | 119 | { | 
|---|
|  | 120 | size_t elementno = 0; | 
|---|
| [f01769] | 121 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 122 | getAtom(AtomById(atomicid)); | 
|---|
| [c60665] | 123 | const element *_type = NULL; | 
|---|
| [917659] | 124 | if (_atom != NULL) { | 
|---|
| [c60665] | 125 | _type = _atom->getType(); | 
|---|
| [7188b1] | 126 | } else { | 
|---|
| [917659] | 127 | ELOG(2, "Atom with id "+toString(atomicid)+" is already gone."); | 
|---|
| [7188b1] | 128 | } | 
|---|
| [c60665] | 129 | if (_type != NULL) { | 
|---|
|  | 130 | elementno = _type->getAtomicNumber(); | 
|---|
|  | 131 | } else { // if no element yet, set to hydrogen | 
|---|
|  | 132 | elementno = 1; | 
|---|
|  | 133 | } | 
|---|
|  | 134 | LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new element number is "+toString(elementno)+"."); | 
|---|
|  | 135 |  | 
|---|
|  | 136 | // set materials | 
|---|
|  | 137 | QGLMaterial *elementmaterial = getMaterial(elementno); | 
|---|
|  | 138 | ASSERT(elementmaterial != NULL, | 
|---|
|  | 139 | "GLMoleculeObject_atom::GLMoleculeObject_atom() - QGLMaterial ref from getter function is NULL."); | 
|---|
|  | 140 | setMaterial(elementmaterial); | 
|---|
|  | 141 |  | 
|---|
|  | 142 | // set scale | 
|---|
|  | 143 | double radius = 0.; | 
|---|
|  | 144 | if (_type != NULL) { | 
|---|
|  | 145 | radius = _type->getVanDerWaalsRadius(); | 
|---|
|  | 146 | } else { | 
|---|
|  | 147 | radius = 0.5; | 
|---|
|  | 148 | } | 
|---|
|  | 149 | setScale( radius / 4. ); | 
|---|
| [f115cc] | 150 |  | 
|---|
|  | 151 | uptodateElement = true; | 
|---|
| [7188b1] | 152 | } | 
|---|
|  | 153 |  | 
|---|
|  | 154 | void GLMoleculeObject_atom::resetIndex() | 
|---|
|  | 155 | { | 
|---|
| [30cd0d] | 156 | int oldId = objectId(); | 
|---|
| [917659] | 157 | LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(atomicid)+"."); | 
|---|
|  | 158 | setObjectId(atomicid); | 
|---|
| [30cd0d] | 159 |  | 
|---|
| [917659] | 160 | emit indexChanged(this, oldId, atomicid); | 
|---|
| [7188b1] | 161 | } | 
|---|
|  | 162 |  | 
|---|
|  | 163 | void GLMoleculeObject_atom::resetProperties() | 
|---|
|  | 164 | { | 
|---|
| [907636] | 165 | // set position | 
|---|
| [7188b1] | 166 | resetPosition(); | 
|---|
| [907636] | 167 |  | 
|---|
| [7188b1] | 168 | // set element | 
|---|
|  | 169 | resetElement(); | 
|---|
| [907636] | 170 |  | 
|---|
|  | 171 | // set the object's id | 
|---|
| [7188b1] | 172 | resetIndex(); | 
|---|
| [d53902] | 173 |  | 
|---|
|  | 174 | // selected? | 
|---|
| [917659] | 175 | setSelected(World::getInstance().isAtomSelected(atomicid)); | 
|---|
| [7188b1] | 176 | } | 
|---|
| [907636] | 177 |  | 
|---|
| [f115cc] | 178 | void GLMoleculeObject_atom::draw(QGLPainter *painter, const QVector4D &cameraPlane) | 
|---|
|  | 179 | { | 
|---|
|  | 180 | // hook to update prior to painting | 
|---|
|  | 181 | if (!uptodatePosition) | 
|---|
|  | 182 | resetPosition(); | 
|---|
|  | 183 | if (!uptodateElement) | 
|---|
|  | 184 | resetElement(); | 
|---|
|  | 185 |  | 
|---|
|  | 186 | // call old hook to do the actual paining | 
|---|
|  | 187 | GLMoleculeObject::draw(painter, cameraPlane); | 
|---|
|  | 188 | } | 
|---|
|  | 189 |  | 
|---|
| [7188b1] | 190 | void GLMoleculeObject_atom::subjectKilled(Observable *publisher) | 
|---|
| [c736fe] | 191 | { | 
|---|
| [917659] | 192 | // remove id such that we don't sign off accidentally from a different atom | 
|---|
|  | 193 | const_cast<atomId_t &>(atomicid) = -1; | 
|---|
| [c736fe] | 194 | } | 
|---|
| [06ebf5] | 195 |  | 
|---|
| [7188b1] | 196 | void GLMoleculeObject_atom::recieveNotification(Observable *publisher, Notification_ptr notification) | 
|---|
|  | 197 | { | 
|---|
| [f01769] | 198 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 199 | getAtom(AtomById(atomicid)); | 
|---|
| [d53902] | 200 | if (publisher == dynamic_cast<const Observable*>(_atom)){ | 
|---|
|  | 201 | // notofication from atom | 
|---|
| [57a770] | 202 | #ifdef LOG_OBSERVER | 
|---|
| [708277] | 203 | observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this)) | 
|---|
| [d53902] | 204 | << " received notification from atom " << _atom->getId() << " for channel " | 
|---|
|  | 205 | << notification->getChannelNo() << "."; | 
|---|
| [57a770] | 206 | #endif | 
|---|
| [d53902] | 207 | switch (notification->getChannelNo()) { | 
|---|
|  | 208 | case AtomObservable::ElementChanged: | 
|---|
| [f115cc] | 209 | uptodateElement = false; | 
|---|
| [d53902] | 210 | break; | 
|---|
|  | 211 | case AtomObservable::IndexChanged: | 
|---|
|  | 212 | resetIndex(); | 
|---|
|  | 213 | break; | 
|---|
|  | 214 | case AtomObservable::PositionChanged: | 
|---|
| [f115cc] | 215 | uptodatePosition = false; | 
|---|
| [d53902] | 216 | break; | 
|---|
|  | 217 | case AtomObservable::BondsAdded: | 
|---|
| [2ad1ec] | 218 | { | 
|---|
| [f01769] | 219 | const atom * const _atom = const_cast<const World &>(World::getInstance()). | 
|---|
|  | 220 | getAtom(AtomById(atomicid)); | 
|---|
| [917659] | 221 | if (_atom != NULL) { | 
|---|
| [f115cc] | 222 | // make sure position is up-to-date | 
|---|
|  | 223 | if (!uptodatePosition) | 
|---|
|  | 224 | resetPosition(); | 
|---|
| [d53902] | 225 | ASSERT(!_atom->getListOfBonds().empty(), | 
|---|
|  | 226 | "GLMoleculeObject_atom::recieveNotification() - received BondsAdded but ListOfBonds is empty."); | 
|---|
| [88c8ec] | 227 | const bond::ptr _bond = *(_atom->getListOfBonds().rbegin()); | 
|---|
| [d53902] | 228 | const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ? | 
|---|
|  | 229 | GLMoleculeObject_bond::left : GLMoleculeObject_bond::right; | 
|---|
|  | 230 | emit BondsInserted(_bond, side); | 
|---|
| [917659] | 231 | } else { | 
|---|
|  | 232 | ELOG(2, "Atom with id "+toString(atomicid)+" is already gone."); | 
|---|
| [d53902] | 233 | } | 
|---|
| [917659] | 234 | break; | 
|---|
|  | 235 | } | 
|---|
| [d53902] | 236 | default: | 
|---|
|  | 237 | //setProperties(); | 
|---|
|  | 238 | break; | 
|---|
|  | 239 | } | 
|---|
| [89b992] | 240 | }else if (static_cast<World *>(publisher) == World::getPointer()) { | 
|---|
| [d53902] | 241 | // notification from world | 
|---|
|  | 242 | #ifdef LOG_OBSERVER | 
|---|
| [708277] | 243 | observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this)) | 
|---|
| [d53902] | 244 | << " received notification from world for channel " | 
|---|
|  | 245 | << notification->getChannelNo() << "."; | 
|---|
|  | 246 | #endif | 
|---|
|  | 247 | switch (notification->getChannelNo()) { | 
|---|
|  | 248 | case World::SelectionChanged: | 
|---|
| [704d59] | 249 | if (_atom != NULL) | 
|---|
|  | 250 | setSelected(World::getInstance().isSelected(_atom)); | 
|---|
| [d53902] | 251 | break; | 
|---|
|  | 252 | default: | 
|---|
| [2ad1ec] | 253 | break; | 
|---|
| [d53902] | 254 | } | 
|---|
| [7188b1] | 255 | } | 
|---|
| [06ebf5] | 256 | } | 
|---|
|  | 257 |  | 
|---|
|  | 258 | void GLMoleculeObject_atom::wasClicked() | 
|---|
|  | 259 | { | 
|---|
| [917659] | 260 | LOG(4, "INFO: GLMoleculeObject_atom: atom " << atomicid << " has been clicked"); | 
|---|
|  | 261 | emit clicked(atomicid); | 
|---|
| [907636] | 262 | } | 
|---|