- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.cpp
ra2a2f7 r52cd7b 41 41 42 42 #include <Qt3D/qglscenenode.h> 43 #include <Qt3D/qglbuilder.h> 43 44 44 45 #include "CodePatterns/MemDebug.hpp" … … 54 55 #include "Element/element.hpp" 55 56 #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" 56 64 #include "World.hpp" 57 65 58 GLMoleculeObject_molecule::GLMoleculeObject_molecule(QGLSceneNode *mesh[], QObject *parent, const molecule *molref) : 59 GLMoleculeObject(mesh, parent), 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), 60 134 Observer(std::string("GLMoleculeObject_molecule")+toString(molref->getId())), 61 _molecule(molref) 135 isBoundingBoxUptodate(true), 136 isSignedOn(false), 137 _molecule(molref), 138 TesselationHullUptodate(true), 139 hoverAtom(NULL) 62 140 { 63 141 // 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; 64 146 /*molref->signOn(this, AtomObservable::IndexChanged); 65 147 molref->signOn(this, AtomObservable::PositionChanged); … … 69 151 World::getInstance().signOn(this, World::SelectionChanged); 70 152 updateBoundingBox(); 153 154 // initially, atoms and bonds should be visible 155 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 visible 188 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())); 71 196 } 72 197 73 198 GLMoleculeObject_molecule::~GLMoleculeObject_molecule() 74 199 { 200 if (isSignedOn) { 201 _molecule->signOff(this, molecule::AtomInserted); 202 _molecule->signOff(this, molecule::AtomRemoved); 203 _molecule->signOff(this, molecule::AtomMoved); 204 } 75 205 /*_atom->signOff(this, AtomObservable::IndexChanged); 76 206 _atom->signOff(this, AtomObservable::PositionChanged); … … 80 210 } 81 211 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 scene 223 atomicid = (*atomiter)->getId(); 224 atomInserted(atomicid); 225 226 // create bond objects in scene 227 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 time 238 setObjectId(atomicid); 239 } 240 } 241 242 void GLMoleculeObject_molecule::addAtomBonds( 243 const bond::ptr &_bond, 244 const GLMoleculeObject_bond::SideOfBond _side 245 ) 246 { 247 bool bond_present = false; 248 const BondIds ids = getBondIds(_bond, _side); 249 // check whether bond is not present already 250 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 present 269 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 exists 289 const atomId_t atomid = (*atomiter)->getId(); 290 const bool atom_present = AtomsinSceneMap.count(atomid); 291 if (!atom_present) 292 atomInserted((*atomiter)->getId()); 293 else 294 AtomsinSceneMap[atomid]->resetPosition(); 295 296 297 // create bond objects in scene 298 addAtomBonds(*atomiter); 299 } 300 } 301 } 302 82 303 void GLMoleculeObject_molecule::updateBoundingBox() 83 304 { 305 isBoundingBoxUptodate = true; 84 306 Shape shape = _molecule->getBoundingSphere(); 85 307 Vector v = shape.getCenter(); … … 97 319 98 320 void GLMoleculeObject_molecule::subjectKilled(Observable *publisher) 99 {} 321 { 322 isSignedOn = false; 323 } 100 324 101 325 void GLMoleculeObject_molecule::recieveNotification(Observable *publisher, Notification_ptr notification) … … 108 332 << notification->getChannelNo() << "."; 109 333 #endif 334 switch (notification->getChannelNo()) { 335 case molecule::AtomInserted: 336 { 337 const atomId_t _id = _molecule->lastChanged()->getId(); 338 #ifdef LOG_OBSERVER 339 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted."; 340 #endif 341 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_OBSERVER 350 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed."; 351 #endif 352 TesselationHullUptodate = false; 353 isBoundingBoxUptodate = false; 354 atomRemoved(_id); 355 break; 356 } 357 case molecule::AtomMoved: 358 { 359 #ifdef LOG_OBSERVER 360 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 #endif 363 TesselationHullUptodate = false; 364 isBoundingBoxUptodate = false; 365 break; 366 } 367 default: 368 break; 369 } 110 370 }else{ 111 371 // notification from world … … 125 385 } 126 386 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 bonds 404 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 else 416 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 else 425 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 selection 454 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 add 476 */ 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 bonds 503 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 remove 514 */ 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 ~bond 519 520 if (m_objectId == _id) 521 setObjectId(-1); 522 523 // remove atoms 524 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 add 584 * @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 remove 612 */ 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 bond 618 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 itself 627 //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 now 636 if (value) 637 updateTesselationHull(); 638 // then emit onward 639 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.