- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp
r52cd7b ra2a2f7 41 41 42 42 #include <Qt3D/qglscenenode.h> 43 #include <Qt3D/qglbuilder.h>44 43 45 44 #include "CodePatterns/MemDebug.hpp" … … 55 54 #include "Element/element.hpp" 56 55 #include "LinearAlgebra/Vector.hpp" 57 #include "LinkedCell/PointCloudAdaptor.hpp"58 #include "LinkedCell/linkedcell.hpp"59 #include "Tesselation/tesselation.hpp"60 #include "Tesselation/BoundaryLineSet.hpp"61 #include "Tesselation/BoundaryTriangleSet.hpp"62 #include "Tesselation/CandidateForTesselation.hpp"63 #include "Atom/TesselPoint.hpp"64 56 #include "World.hpp" 65 57 66 #include "GLMoleculeObject_atom.hpp" 67 68 static QGLSceneNode *createMoleculeMesh(const molecule *molref, QObject *parent) 69 { 70 // Shape shape = molref->getBoundingSphere(); 71 double minradius = 2.; // TODO: set to maximum bond length value 72 LOG(3, "DEBUG: Molecule fits into sphere of radius " << minradius); 73 if (minradius < 1.) 74 minradius = 1.; 75 76 QGeometryData geo; 77 // we need at least three points for tesselation 78 if (molref->getAtomCount() >= 3) { 79 // Tesselate the points. 80 Tesselation T; 81 PointCloudAdaptor<molecule> cloud(const_cast<molecule *>(molref), molref->getName()); 82 T(cloud, minradius); 83 84 // Fill the points into a Qt geometry. 85 LinkedCell_deprecated LinkedList(cloud, minradius); 86 std::map<int, int> indices; 87 std::map<int, Vector> normals; 88 int index = 0; 89 for (PointMap::const_iterator piter = T.PointsOnBoundary.begin(); 90 piter != T.PointsOnBoundary.end(); ++piter) { 91 const Vector &point = piter->second->getPosition(); 92 // add data to the primitive 93 geo.appendVertex(QVector3D(point[0], point[1], point[2])); 94 Vector normalvector; 95 for (LineMap::const_iterator lineiter = piter->second->lines.begin(); 96 lineiter != piter->second->lines.end(); ++lineiter) 97 for (TriangleMap::const_iterator triangleiter = lineiter->second->triangles.begin(); 98 triangleiter != lineiter->second->triangles.end(); ++triangleiter) 99 normalvector += 100 triangleiter->second->NormalVector; 101 normalvector.Normalize(); 102 geo.appendNormal(QVector3D(normalvector[0], normalvector[1], normalvector[2])); 103 geo.appendColor(QColor(1, 1, 1, 1)); 104 geo.appendTexCoord(QVector2D(0, 0)); 105 indices.insert( std::make_pair( piter->second->getNr(), index++)); 106 } 107 108 // Fill the tesselated triangles into the geometry. 109 for (TriangleMap::const_iterator runner = T.TrianglesOnBoundary.begin(); 110 runner != T.TrianglesOnBoundary.end(); runner++) { 111 int v[3]; 112 for (size_t i=0; i<3; ++i) 113 v[i] = runner->second->endpoints[i]->getNr(); 114 115 // Sort the vertices so the triangle is clockwise (relative to the normal vector). 116 Vector cross = T.PointsOnBoundary[v[1]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition(); 117 cross.VectorProduct(T.PointsOnBoundary[v[2]]->getPosition() - T.PointsOnBoundary[v[0]]->getPosition()); 118 if (cross.ScalarProduct(runner->second->NormalVector) > 0) 119 geo.appendIndices(indices[v[0]], indices[v[1]], indices[v[2]]); 120 else 121 geo.appendIndices(indices[v[0]], indices[v[2]], indices[v[1]]); 122 } 123 } 124 125 // Build a mesh from the geometry. 126 QGLBuilder builder; 127 builder.addTriangles(geo); 128 QGLSceneNode *mesh = builder.finalizedSceneNode(); 129 return mesh; 130 } 131 132 GLMoleculeObject_molecule::GLMoleculeObject_molecule(QObject *parent, const molecule *molref) : 133 GLMoleculeObject(createMoleculeMesh(molref, parent), parent), 58 GLMoleculeObject_molecule::GLMoleculeObject_molecule(QGLSceneNode *mesh[], QObject *parent, const molecule *molref) : 59 GLMoleculeObject(mesh, parent), 134 60 Observer(std::string("GLMoleculeObject_molecule")+toString(molref->getId())), 135 isBoundingBoxUptodate(true), 136 isSignedOn(false), 137 _molecule(molref), 138 TesselationHullUptodate(true), 139 hoverAtom(NULL) 61 _molecule(molref) 140 62 { 141 63 // sign on as observer (obtain non-const instance before) 142 _molecule->signOn(this, molecule::AtomInserted);143 _molecule->signOn(this, molecule::AtomRemoved);144 _molecule->signOn(this, molecule::AtomMoved);145 isSignedOn = true;146 64 /*molref->signOn(this, AtomObservable::IndexChanged); 147 65 molref->signOn(this, AtomObservable::PositionChanged); … … 151 69 World::getInstance().signOn(this, World::SelectionChanged); 152 70 updateBoundingBox(); 153 154 // initially, atoms and bonds should be visible155 m_visible = false;156 157 init();158 159 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));160 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));161 162 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));163 }164 165 GLMoleculeObject_molecule::GLMoleculeObject_molecule(QGLSceneNode *mesh[], QObject *parent, const molecule *molref) :166 GLMoleculeObject(mesh, parent),167 Observer(std::string("GLMoleculeObject_molecule")+toString(molref->getId())),168 isBoundingBoxUptodate(true),169 isSignedOn(false),170 _molecule(molref),171 TesselationHullUptodate(true),172 hoverAtom(NULL)173 {174 // sign on as observer (obtain non-const instance before)175 _molecule->signOn(this, molecule::AtomInserted);176 _molecule->signOn(this, molecule::AtomRemoved);177 _molecule->signOn(this, molecule::AtomMoved);178 isSignedOn = true;179 /*molref->signOn(this, AtomObservable::IndexChanged);180 molref->signOn(this, AtomObservable::PositionChanged);181 molref->signOn(this, AtomObservable::ElementChanged);182 molref->signOn(this, AtomObservable::BondsAdded);*/183 setMaterial(getMaterial(1));184 World::getInstance().signOn(this, World::SelectionChanged);185 updateBoundingBox();186 187 // initially, atoms and bonds should be visible188 m_visible = false;189 190 init();191 192 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));193 connect (this, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));194 195 connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));196 71 } 197 72 198 73 GLMoleculeObject_molecule::~GLMoleculeObject_molecule() 199 74 { 200 if (isSignedOn) {201 _molecule->signOff(this, molecule::AtomInserted);202 _molecule->signOff(this, molecule::AtomRemoved);203 _molecule->signOff(this, molecule::AtomMoved);204 }205 75 /*_atom->signOff(this, AtomObservable::IndexChanged); 206 76 _atom->signOff(this, AtomObservable::PositionChanged); … … 210 80 } 211 81 212 /** Initialise the WorldScene with molecules and atoms from World.213 *214 */215 void GLMoleculeObject_molecule::init()216 {217 if (_molecule->begin() != _molecule->end()) {218 int atomicid = -1;219 for (molecule::const_iterator atomiter = _molecule->begin();220 atomiter != _molecule->end();221 atomiter++) {222 // create atom objects in scene223 atomicid = (*atomiter)->getId();224 atomInserted(atomicid);225 226 // create bond objects in scene227 const BondList &bondlist = (*atomiter)->getListOfBonds();228 for (BondList::const_iterator bonditer = bondlist.begin();229 bonditer != bondlist.end();230 ++bonditer) {231 const bond::ptr _bond = *bonditer;232 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == *atomiter) ?233 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;234 bondInserted(_bond, side);235 }236 }237 // set id to one of the atom's as either mol or atoms is present at the same time238 setObjectId(atomicid);239 }240 }241 242 void GLMoleculeObject_molecule::addAtomBonds(243 const bond::ptr &_bond,244 const GLMoleculeObject_bond::SideOfBond _side245 )246 {247 bool bond_present = false;248 const BondIds ids = getBondIds(_bond, _side);249 // check whether bond is not present already250 bond_present = BondsinSceneMap.count(ids);251 if (!bond_present)252 bondInserted(_bond, _side);253 else {254 BondsinSceneMap[ids]->resetPosition();255 BondsinSceneMap[ids]->resetWidth();256 }257 }258 259 void GLMoleculeObject_molecule::addAtomBonds(260 const atom *_atom)261 {262 const bool atom_present = AtomsinSceneMap.count(_atom->getId());263 const BondList &bondlist = _atom->getListOfBonds();264 for (BondList::const_iterator bonditer = bondlist.begin();265 (bonditer != bondlist.end()) && atom_present;266 ++bonditer) {267 const bond::ptr _bond = *bonditer;268 // check if OtherAtom's sphere is already present269 const atom *OtherAtom = _bond->GetOtherAtom(_atom);270 const bool otheratom_present = AtomsinSceneMap.count(OtherAtom->getId());271 if (otheratom_present && atom_present) {272 const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ?273 GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;274 const GLMoleculeObject_bond::SideOfBond otherside = (_bond->leftatom == _atom) ?275 GLMoleculeObject_bond::right : GLMoleculeObject_bond::left;276 addAtomBonds(_bond, side);277 addAtomBonds(_bond, otherside);278 }279 }280 }281 282 void GLMoleculeObject_molecule::reinit()283 {284 if (_molecule->getAtomCount() > 0) {285 for (molecule::const_iterator atomiter = _molecule->begin();286 atomiter != _molecule->end();287 atomiter++) {288 // check whether atom already exists289 const atomId_t atomid = (*atomiter)->getId();290 const bool atom_present = AtomsinSceneMap.count(atomid);291 if (!atom_present)292 atomInserted((*atomiter)->getId());293 else294 AtomsinSceneMap[atomid]->resetPosition();295 296 297 // create bond objects in scene298 addAtomBonds(*atomiter);299 }300 }301 }302 303 82 void GLMoleculeObject_molecule::updateBoundingBox() 304 83 { 305 isBoundingBoxUptodate = true;306 84 Shape shape = _molecule->getBoundingSphere(); 307 85 Vector v = shape.getCenter(); … … 319 97 320 98 void GLMoleculeObject_molecule::subjectKilled(Observable *publisher) 321 { 322 isSignedOn = false; 323 } 99 {} 324 100 325 101 void GLMoleculeObject_molecule::recieveNotification(Observable *publisher, Notification_ptr notification) … … 332 108 << notification->getChannelNo() << "."; 333 109 #endif 334 switch (notification->getChannelNo()) {335 case molecule::AtomInserted:336 {337 const atomId_t _id = _molecule->lastChanged()->getId();338 #ifdef LOG_OBSERVER339 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";340 #endif341 TesselationHullUptodate = false;342 isBoundingBoxUptodate = false;343 atomInserted(_id);344 break;345 }346 case World::AtomRemoved:347 {348 const atomId_t _id = _molecule->lastChanged()->getId();349 #ifdef LOG_OBSERVER350 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed.";351 #endif352 TesselationHullUptodate = false;353 isBoundingBoxUptodate = false;354 atomRemoved(_id);355 break;356 }357 case molecule::AtomMoved:358 {359 #ifdef LOG_OBSERVER360 const atomId_t _id = _molecule->lastChanged()->getId();361 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";362 #endif363 TesselationHullUptodate = false;364 isBoundingBoxUptodate = false;365 break;366 }367 default:368 break;369 }370 110 }else{ 371 111 // notification from world … … 385 125 } 386 126 387 void GLMoleculeObject_molecule::initialize(QGLView *view, QGLPainter *painter)388 {389 // Initialize all of the mesh objects that we have as children.390 if (m_visible) {391 GLMoleculeObject::initialize(view, painter);392 } else {393 foreach (QObject *obj, children()) {394 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);395 if (meshobj)396 meshobj->initialize(view, painter);397 }398 }399 }400 401 void GLMoleculeObject_molecule::draw(QGLPainter *painter, const QVector4D &cameraPlane)402 {403 // draw either molecule's mesh or all atoms and bonds404 if (m_visible) {405 updateTesselationHull();406 407 painter->modelViewMatrix().push();408 409 // Apply the material and effect to the painter.410 QGLMaterial *material;411 if (m_hovering)412 material = m_hoverMaterial;413 else if (m_selected)414 material = m_selectionMaterial;415 else416 material = m_material;417 418 ASSERT(material, "GLMoleculeObject::draw: chosen material is NULL");419 420 painter->setColor(material->diffuseColor());421 painter->setFaceMaterial(QGL::AllFaces, material);422 if (m_effect)423 painter->setUserEffect(m_effect);424 else425 painter->setStandardEffect(QGL::LitMaterial);426 427 // Mark the object for object picking purposes.428 int prevObjectId = painter->objectPickId();429 if (m_objectId != -1)430 painter->setObjectPickId(m_objectId);431 432 m_mesh[0]->draw(painter);433 434 // Turn off the user effect, if present.435 if (m_effect)436 painter->setStandardEffect(QGL::LitMaterial);437 438 // Revert to the previous object identifier.439 painter->setObjectPickId(prevObjectId);440 441 // Restore the modelview matrix.442 painter->modelViewMatrix().pop();443 444 // GLMoleculeObject::draw(painter, cameraPlane);445 } else {446 // Draw all of the mesh objects that we have as children.447 foreach (QObject *obj, children()) {448 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);449 if (meshobj)450 meshobj->draw(painter, cameraPlane);451 }452 453 // update bounding box prior to selection454 if (!isBoundingBoxUptodate)455 updateBoundingBox();456 457 painter->modelViewMatrix().push();458 painter->modelViewMatrix().translate(m_position);459 if ((m_scaleX != 1.0f) || (m_scaleY != 1.0f) || (m_scaleZ != 1.0f))460 painter->modelViewMatrix().scale(m_scaleX, m_scaleY, m_scaleZ);461 if (m_rotationAngle != 0.0f)462 painter->modelViewMatrix().rotate(m_rotationAngle, m_rotationVector);463 464 // Draw a box around the mesh, if selected.465 if (m_selected)466 drawSelectionBox(painter);467 468 // Restore the modelview matrix.469 painter->modelViewMatrix().pop();470 }471 }472 473 /** Adds an atom of this molecule to the scene.474 *475 * @param _atom atom to add476 */477 void GLMoleculeObject_molecule::atomInserted(const atomicNumber_t _id)478 {479 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "+toString(_id)+".");480 GLMoleculeObject_atom *atomObject = new GLMoleculeObject_atom(GLMoleculeObject::meshSphere, this, _id);481 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);482 ASSERT(iter == AtomsinSceneMap.end(),483 "GLWorldScene::atomAdded() - same atom with id "+toString(_id)+" added again.");484 AtomsinSceneMap.insert( make_pair(_id, atomObject) );485 486 qRegisterMetaType<atomId_t>("atomId_t");487 qRegisterMetaType<bond::ptr>("bond::ptr");488 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");489 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SIGNAL(atomClicked(atomId_t)));490 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));491 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));492 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));493 connect (atomObject, SIGNAL(selectionChanged()), this, SIGNAL(changed()));494 connect (atomObject, SIGNAL(BondsInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)), this, SLOT(bondInserted(const bond::ptr , const GLMoleculeObject_bond::SideOfBond)));495 connect (atomObject, SIGNAL(indexChanged(GLMoleculeObject_atom*, int, int)), this, SIGNAL(changeAtomId(GLMoleculeObject_atom*, int, int)));496 497 isBoundingBoxUptodate = false;498 499 if (m_objectId == -1)500 setObjectId(_id);501 502 // add all bonds503 const atom *Walker = World::getInstance().getAtom(AtomById(_id));504 addAtomBonds(Walker);505 506 emit changeOccured();507 }508 509 /** Removes an atom of this molecule from the scene.510 *511 * We just the id as the atom might have already been destroyed.512 *513 * @param _id id of atom to remove514 */515 void GLMoleculeObject_molecule::atomRemoved(const atomicNumber_t _id)516 {517 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_id)+".");518 // bonds are removed by signal coming from ~bond519 520 if (m_objectId == _id)521 setObjectId(-1);522 523 // remove atoms524 AtomNodeMap::iterator iter = AtomsinSceneMap.find(_id);525 ASSERT(iter != AtomsinSceneMap.end(),526 "GLWorldScene::atomRemoved() - atom "+toString(_id)+" not on display.");527 GLMoleculeObject_atom *atomObject = iter->second;528 atomObject->disconnect();529 AtomsinSceneMap.erase(iter);530 delete atomObject;531 532 isBoundingBoxUptodate = false;533 534 emit changeOccured();535 }536 537 void GLMoleculeObject_molecule::hoverChangedSignalled(GLMoleculeObject *ob)538 {539 // Find the atom, ob corresponds to.540 hoverAtom = NULL;541 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);542 if (atomObject){543 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){544 if (iter->second == atomObject)545 hoverAtom = World::getInstance().getAtom(AtomById(iter->first));546 }547 548 // Propagate signal.549 emit hoverChanged(*hoverAtom);550 } else {551 // Find the atom, ob corresponds to.552 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);553 if (moleculeObject == this){554 // Propagate signal.555 emit hoverChanged(*_molecule, 0);556 }557 }558 }559 560 561 /** Helper function to get bond ids in the correct order for BondNodeMap.562 *563 * \return pair of ids in correct order.564 */565 GLMoleculeObject_molecule::BondIds GLMoleculeObject_molecule::getBondIds(566 const bond::ptr _bond,567 const enum GLMoleculeObject_bond::SideOfBond _side)568 {569 BondIds ids;570 switch (_side) {571 case GLMoleculeObject_bond::left:572 ids = std::make_pair(_bond->leftatom->getId(), _bond->rightatom->getId());573 break;574 case GLMoleculeObject_bond::right:575 ids = std::make_pair(_bond->rightatom->getId(), _bond->leftatom->getId());576 break;577 }578 return ids;579 }580 581 /** Adds a bond to the scene.582 *583 * @param _bond bond to add584 * @param side which side of the bond (left or right)585 */586 void GLMoleculeObject_molecule::bondInserted(const bond::ptr _bond, const enum GLMoleculeObject_bond::SideOfBond _side)587 {588 LOG(3, "INFO: GLWorldScene::bondInserted() - Adding bond "+toString(*_bond)+".");589 //LOG(4, "INFO: Currently present bonds " << BondsinSceneMap << ".");590 591 const BondIds ids = getBondIds(_bond, _side);592 BondNodeMap::iterator iter = BondsinSceneMap.find(ids);593 if (iter == BondsinSceneMap.end()) {594 GLMoleculeObject_bond * bondObject =595 new GLMoleculeObject_bond(GLMoleculeObject::meshCylinder, this, _bond, _side);596 connect (597 bondObject, SIGNAL(BondRemoved(const atomId_t, const atomId_t)),598 this, SLOT(bondRemoved(const atomId_t, const atomId_t)));599 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));600 BondsinSceneMap.insert( make_pair(ids, bondObject) );601 // BondIdsinSceneMap.insert( Leftids );602 } else {603 iter->second->resetPosition();604 iter->second->resetWidth();605 }606 emit changeOccured();607 }608 609 /** Removes a bond from the scene.610 *611 * @param _bond bond to remove612 */613 void GLMoleculeObject_molecule::bondRemoved(const atomId_t leftnr, const atomId_t rightnr)614 {615 LOG(3, "INFO: GLWorldScene::bondRemoved() - Removing bond between "+toString(leftnr)+" and "+toString(rightnr)+".");616 {617 // left bond618 const BondIds Leftids( make_pair(leftnr, rightnr) );619 BondNodeMap::iterator leftiter = BondsinSceneMap.find( Leftids );620 ASSERT(leftiter != BondsinSceneMap.end(),621 "GLWorldScene::bondRemoved() - bond "+toString(leftnr)+"-"622 +toString(rightnr)+" not on display.");623 GLMoleculeObject_bond *bondObject = leftiter->second;624 bondObject->disconnect();625 BondsinSceneMap.erase(leftiter);626 delete bondObject; // is done by signal from bond itself627 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");628 }629 630 emit changeOccured();631 }632 633 void GLMoleculeObject_molecule::setVisible(bool value)634 {635 // first update the mesh if we are going to be visible now636 if (value)637 updateTesselationHull();638 // then emit onward639 GLMoleculeObject::setVisible(value);640 }641 642 void GLMoleculeObject_molecule::updateTesselationHull()643 {644 if (!TesselationHullUptodate) {645 updateMesh(createMoleculeMesh(_molecule, parent()));646 TesselationHullUptodate = true;647 }648 }649 650 std::ostream &operator<<(std::ostream &ost, const GLMoleculeObject_molecule::BondIds &t)651 {652 ost << t.first << "," << t.second;653 return ost;654 }655 656 void GLMoleculeObject_molecule::wasClicked()657 {658 LOG(4, "INFO: GLMoleculeObject_molecule: atom " << _molecule->getId() << " has been clicked");659 emit moleculeClicked(_molecule->getId());660 }
Note:
See TracChangeset
for help on using the changeset viewer.