1 /********************************************************************** 2 obiter.cpp - STL-style iterators for Open Babel 3 4 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc. 5 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison 6 7 This file is part of the Open Babel project. 8 For more information, see <http://openbabel.org/> 9 10 This program 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 version 2 of the License. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 ***********************************************************************/ 19 #include <openbabel/babelconfig.h> 20 21 #include <vector> 22 23 #include <openbabel/mol.h> 24 #include <openbabel/atom.h> 25 #include <openbabel/bond.h> 26 #include <openbabel/generic.h> 27 #include <openbabel/obiter.h> 28 29 using namespace std; 30 31 namespace OpenBabel 32 { 33 34 /** \class OBMolAtomIter obiter.h <openbabel/obiter.h> 35 36 To facilitate iteration through all atoms in a molecule, without resorting 37 to atom indexes (which <strong>will</strong> change in the future), a 38 variety of iterator methods are provided. 39 40 This has been made significantly easier by a series of macros in the 41 obiter.h header file: 42 43 \code 44 \#define FOR_ATOMS_OF_MOL(a,m) for( OBMolAtomIter a(m); a; ++a ) 45 \endcode 46 47 Here is an example: 48 \code 49 #include <openbabel/obiter.h> 50 #include <openbabel/mol.h> 51 52 OpenBabel::OBMol mol; 53 double exactMass = 0.0; 54 FOR_ATOMS_OF_MOL(a, mol) 55 { 56 // The variable a behaves like OBAtom* when used with -> and * but 57 // but needs to be explicitly converted when appearing as a parameter 58 // in a function call - use &*a 59 60 exactMass += a->GetExactMass(); 61 } 62 \endcode 63 **/ 64 OBMolAtomIter(OBMol * mol)65 OBMolAtomIter::OBMolAtomIter(OBMol *mol) 66 { 67 _parent = mol; 68 _ptr = _parent->BeginAtom(_i); 69 } 70 OBMolAtomIter(OBMol & mol)71 OBMolAtomIter::OBMolAtomIter(OBMol &mol) 72 { 73 _parent = &mol; 74 _ptr = _parent->BeginAtom(_i); 75 } 76 OBMolAtomIter(const OBMolAtomIter & ai)77 OBMolAtomIter::OBMolAtomIter(const OBMolAtomIter &ai) 78 { 79 _parent = ai._parent; 80 _ptr = ai._ptr; 81 _i = ai._i; 82 } 83 operator =(const OBMolAtomIter & ai)84 OBMolAtomIter& OBMolAtomIter::operator=(const OBMolAtomIter &ai) 85 { 86 if (this != &ai) 87 { 88 _parent = ai._parent; 89 _ptr = ai._ptr; 90 _i = ai._i; 91 } 92 return *this; 93 } 94 operator ++()95 OBMolAtomIter& OBMolAtomIter::operator++() 96 { 97 _ptr = _parent->NextAtom(_i); 98 return *this; 99 } 100 operator ++(int)101 OBMolAtomIter OBMolAtomIter::operator++(int) 102 { 103 OBMolAtomIter tmp(*this); 104 operator++(); 105 return tmp; 106 } 107 108 /** \class OBMolAtomDFSIter obiter.h <openbabel/obiter.h> 109 110 \since version 2.1 111 112 To facilitate iteration through all atoms in a molecule, without resorting 113 to atom indexes (which <strong>will</strong> change in the future), a 114 variety of iterator methods are provided. 115 116 This class provides a depth-first search ordering of atoms. When one 117 connected component is exhausted, the iterator will start at another until 118 all atoms are visited. No guarantee is made as to the ordering of 119 iteration through connected components. 120 121 The iterator maintains an internal stack and list of visited 122 atoms. As such it may not be appropriate for memory-constrained 123 situations when iterating through large molecules. 124 125 Use of this iterator has been made significantly easier by a series 126 of macros in the obiter.h header file: 127 128 \code 129 \#define FOR_DFS_OF_MOL(a,m) for( OBMolAtomDFSIter a(m); a; ++a ) 130 \endcode 131 132 Here is an example: 133 \code 134 #include <openbabel/obiter.h> 135 #include <openbabel/mol.h> 136 137 OpenBabel::OBMol mol; 138 FOR_DFS_OF_MOL(a, mol) 139 { 140 // The variable a behaves like OBAtom* when used with -> and * but 141 // but needs to be explicitly converted when appearing as a parameter 142 // in a function call - use &*a 143 144 } 145 \endcode 146 **/ 147 OBMolAtomDFSIter(OBMol * mol,int StartIndex)148 OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol *mol, int StartIndex): 149 _parent(mol), _ptr(_parent->GetAtom(StartIndex)) 150 { 151 if (!_ptr) return; 152 153 _notVisited.Resize(_parent->NumAtoms()); 154 _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1); 155 156 _notVisited.SetBitOff(_ptr->GetIdx() - 1); 157 158 vector<OBBond*>::iterator i; 159 OBAtom *a; 160 161 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 162 { 163 _stack.push(a); 164 _notVisited.SetBitOff(a->GetIdx() - 1); 165 } 166 } 167 OBMolAtomDFSIter(OBMol & mol,int StartIndex)168 OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol &mol, int StartIndex): 169 _parent(&mol), _ptr(_parent->GetAtom(StartIndex)) 170 { 171 if (!_ptr) return; 172 173 _notVisited.Resize(_parent->NumAtoms()); 174 _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1); 175 176 _notVisited.SetBitOff(_ptr->GetIdx() - 1); 177 178 vector<OBBond*>::iterator i; 179 OBAtom *a; 180 181 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 182 { 183 _stack.push(a); 184 _notVisited.SetBitOff(a->GetIdx() - 1); 185 } 186 } 187 OBMolAtomDFSIter(const OBMolAtomDFSIter & ai)188 OBMolAtomDFSIter::OBMolAtomDFSIter(const OBMolAtomDFSIter &ai) 189 { 190 _parent = ai._parent; 191 _ptr = ai._ptr; 192 _notVisited = ai._notVisited; 193 _stack = ai._stack; 194 } 195 operator =(const OBMolAtomDFSIter & ai)196 OBMolAtomDFSIter& OBMolAtomDFSIter::operator=(const OBMolAtomDFSIter &ai) 197 { 198 if (this != &ai) 199 { 200 _parent = ai._parent; 201 _ptr = ai._ptr; 202 _notVisited = ai._notVisited; 203 _stack = ai._stack; 204 } 205 return *this; 206 } 207 operator ++()208 OBMolAtomDFSIter& OBMolAtomDFSIter::operator++() 209 { 210 if (!_stack.empty()) 211 { 212 _ptr = _stack.top(); 213 _stack.pop(); 214 } 215 else // are there any disconnected subgraphs? 216 { 217 int next = _notVisited.FirstBit(); 218 if (next != _notVisited.EndBit()) 219 { 220 _ptr = _parent->GetAtom(next + 1); 221 _notVisited.SetBitOff(next); 222 } 223 else 224 _ptr = nullptr; 225 } 226 227 if (_ptr) 228 { 229 vector<OBBond*>::iterator i; 230 OBAtom *a; 231 232 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 233 if (_notVisited[a->GetIdx() - 1]) 234 { 235 _stack.push(a); 236 _notVisited.SetBitOff(a->GetIdx() - 1); 237 } 238 } 239 240 return *this; 241 } 242 operator ++(int)243 OBMolAtomDFSIter OBMolAtomDFSIter::operator++(int) 244 { 245 OBMolAtomDFSIter tmp(*this); 246 operator++(); 247 return tmp; 248 } 249 250 /** \class OBMolAtomBFSIter obiter.h <openbabel/obiter.h> 251 252 \since version 2.1 253 254 To facilitate iteration through all atoms in a molecule, without resorting 255 to atom indexes (which <strong>will</strong> change in the future), a 256 variety of iterator methods are provided. 257 258 This class provides a breadth-first search ordering of atoms. When one 259 connected component is exhausted, the iterator will start at another until 260 all atoms are visited. No guarantee is made as to the ordering of 261 iteration through connected components. 262 263 The iterator maintains an internal queue and list of visited 264 atoms. As such it may not be appropriate for memory-constrained 265 situations when iterating through large molecules. 266 267 Use of this iterator has been made significantly easier by a series 268 of macros in the obiter.h header file: 269 270 \code 271 \#define FOR_BFS_OF_MOL(a,m) for( OBMolAtomBFSIter a(m); a; ++a ) 272 \endcode 273 274 Here is an example: 275 \code 276 #include <openbabel/obiter.h> 277 #include <openbabel/mol.h> 278 279 OpenBabel::OBMol mol; 280 FOR_BFS_OF_MOL(a, mol) 281 { 282 // The variable a behaves like OBAtom* when used with -> and * but 283 // but needs to be explicitly converted when appearing as a parameter 284 // in a function call - use &*a 285 286 } 287 \endcode 288 **/ 289 OBMolAtomBFSIter(OBMol * mol,int StartIndex)290 OBMolAtomBFSIter::OBMolAtomBFSIter(OBMol *mol, int StartIndex): 291 _parent(mol), _ptr(_parent->GetAtom(StartIndex)) 292 { 293 if (!_ptr) return; 294 295 _notVisited.Resize(_parent->NumAtoms()); 296 _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1); 297 298 _notVisited.SetBitOff(_ptr->GetIdx() - 1); 299 300 // Set up storage for the depths 301 _depth.resize(_parent->NumAtoms() + 1, 0); 302 _depth[_ptr->GetIdx()] = 1; 303 304 vector<OBBond*>::iterator i; 305 OBAtom *a; 306 307 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 308 { 309 _queue.push(a); 310 _depth[a->GetIdx()] = 2; 311 _notVisited.SetBitOff(a->GetIdx() - 1); 312 } 313 } 314 OBMolAtomBFSIter(OBMol & mol,int StartIndex)315 OBMolAtomBFSIter::OBMolAtomBFSIter(OBMol &mol, int StartIndex): 316 _parent(&mol), _ptr(_parent->GetAtom(StartIndex)) 317 { 318 if (!_ptr) return; 319 320 _notVisited.Resize(_parent->NumAtoms()); 321 _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1); 322 323 _notVisited.SetBitOff(_ptr->GetIdx() - 1); 324 325 // Set up storage for the depths 326 _depth.resize(_parent->NumAtoms() + 1, 0); 327 _depth[_ptr->GetIdx()] = 1; 328 329 vector<OBBond*>::iterator i; 330 OBAtom *a; 331 332 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 333 { 334 _queue.push(a); 335 _depth[a->GetIdx()] = 2; 336 _notVisited.SetBitOff(a->GetIdx() - 1); 337 } 338 } 339 OBMolAtomBFSIter(const OBMolAtomBFSIter & ai)340 OBMolAtomBFSIter::OBMolAtomBFSIter(const OBMolAtomBFSIter &ai) 341 { 342 _parent = ai._parent; 343 _ptr = ai._ptr; 344 _notVisited = ai._notVisited; 345 _queue = ai._queue; 346 _depth = ai._depth; 347 } 348 operator =(const OBMolAtomBFSIter & ai)349 OBMolAtomBFSIter& OBMolAtomBFSIter::operator=(const OBMolAtomBFSIter &ai) 350 { 351 if (this != &ai) 352 { 353 _parent = ai._parent; 354 _ptr = ai._ptr; 355 _notVisited = ai._notVisited; 356 _queue = ai._queue; 357 _depth = ai._depth; 358 } 359 return *this; 360 } 361 operator ++()362 OBMolAtomBFSIter& OBMolAtomBFSIter::operator++() 363 { 364 if (!_queue.empty()) 365 { 366 _ptr = _queue.front(); 367 _queue.pop(); 368 } 369 else // are there any disconnected subgraphs? 370 { 371 int next = _notVisited.FirstBit(); 372 if (next != _notVisited.EndBit()) 373 { 374 _ptr = _parent->GetAtom(next + 1); // Atom index issue 375 if (_ptr != nullptr) 376 _depth[_ptr->GetIdx()] = 1; // new island 377 _notVisited.SetBitOff(next); 378 } 379 else 380 _ptr = nullptr; 381 } 382 383 if (_ptr) 384 { 385 vector<OBBond*>::iterator i; 386 OBAtom *a; 387 388 for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) 389 if (_notVisited[a->GetIdx() - 1]) 390 { 391 _queue.push(a); 392 _depth[a->GetIdx()] = _depth[_ptr->GetIdx()] + 1; 393 _notVisited.SetBitOff(a->GetIdx() - 1); 394 } 395 } 396 397 return *this; 398 } 399 operator ++(int)400 OBMolAtomBFSIter OBMolAtomBFSIter::operator++(int) 401 { 402 OBMolAtomBFSIter tmp(*this); 403 operator++(); 404 return tmp; 405 } 406 CurrentDepth() const407 int OBMolAtomBFSIter::CurrentDepth() const 408 { 409 if (_ptr == nullptr) 410 return 0; 411 412 return _depth[_ptr->GetIdx()]; 413 } 414 415 /** \class OBMolBondBFSIter obiter.h <openbabel/obiter.h> 416 417 \since version 2.3 418 419 To facilitate iteration through all bonds in a molecule, without resorting 420 to bond indexes (which <strong>will</strong> change in the future), a 421 variety of iterator methods are provided. 422 423 This class provides a breadth-first search ordering of bonds. When one 424 connected component is exhausted, the iterator will start at another until 425 all bonds are visited. No guarantee is made as to the ordering of 426 iteration through connected components. 427 428 The iterator maintains an internal queue and list of visited 429 atoms. As such it may not be appropriate for memory-constrained 430 situations when iterating through large molecules. 431 432 Use of this iterator has been made significantly easier by a series 433 of macros in the obiter.h header file: 434 435 \code 436 \#define FOR_BONDBFS_OF_MOL(a,m) for( OBMolBondBFSIter a(m); a; ++a ) 437 \endcode 438 439 Here is an example: 440 \code 441 #include <openbabel/obiter.h> 442 #include <openbabel/mol.h> 443 444 OpenBabel::OBMol mol; 445 FOR_BONDBFS_OF_MOL(b, mol) 446 { 447 // The variable b behaves like OBBond* when used with -> and * but 448 // but needs to be explicitly converted when appearing as a parameter 449 // in a function call - use &*a 450 451 } 452 \endcode 453 **/ 454 OBMolBondBFSIter(OBMol * mol,int StartIndex)455 OBMolBondBFSIter::OBMolBondBFSIter(OBMol *mol, int StartIndex): 456 _parent(mol) 457 { 458 unsigned int numbonds = _parent->NumBonds(); 459 if (numbonds == 0) { 460 _ptr = nullptr; // mark as invalid 461 return; 462 } 463 _ptr = _parent->GetBond(StartIndex); 464 if (!_ptr) 465 return; 466 467 _notVisited.Resize(numbonds); 468 _notVisited.SetRangeOn(0, numbonds - 1); 469 470 _notVisited.SetBitOff(_ptr->GetIdx()); 471 472 // Set up storage for the depths 473 _depth.resize(_parent->NumBonds(), 0); 474 _depth[_ptr->GetIdx()] = 1; 475 476 for( OBAtomBondIter b(_ptr->GetBeginAtom()); b; ++b ) 477 { // Loop thru all bonds attached to the start of the bond 478 if (_notVisited[b->GetIdx()]) { // Don't revisit the initial bond 479 _queue.push(&(*b)); 480 _depth[b->GetIdx()] = 2; 481 _notVisited.SetBitOff(b->GetIdx()); 482 } 483 } 484 for( OBAtomBondIter b(_ptr->GetEndAtom()); b; ++b ) 485 { // Loop thru all bonds attached to the end of the bond 486 if (_notVisited[b->GetIdx()]) { // Don't revisit the initial bond 487 _queue.push(&(*b)); 488 _depth[b->GetIdx()] = 2; 489 _notVisited.SetBitOff(b->GetIdx()); 490 } 491 } 492 } 493 OBMolBondBFSIter(OBMol & mol,int StartIndex)494 OBMolBondBFSIter::OBMolBondBFSIter(OBMol &mol, int StartIndex): 495 _parent(&mol) 496 { 497 unsigned int numbonds = _parent->NumBonds(); 498 if (numbonds == 0) { 499 _ptr = nullptr; // mark as invalid 500 return; 501 } 502 _ptr = _parent->GetBond(StartIndex); 503 if (!_ptr) 504 return; 505 506 _notVisited.Resize(numbonds); 507 _notVisited.SetRangeOn(0, numbonds - 1); 508 509 _notVisited.SetBitOff(_ptr->GetIdx()); 510 511 // Set up storage for the depths 512 _depth.resize(numbonds, 0); 513 _depth[_ptr->GetIdx()] = 1; 514 515 for( OBAtomBondIter b(_ptr->GetBeginAtom()); b; ++b ) 516 { // Loop thru all bonds attached to the start of the bond 517 if (_notVisited[b->GetIdx()]) { // Don't revisit the initial bond 518 _queue.push(&(*b)); 519 _depth[b->GetIdx()] = 2; 520 _notVisited.SetBitOff(b->GetIdx()); 521 } 522 } 523 for( OBAtomBondIter b(_ptr->GetEndAtom()); b; ++b ) 524 { // Loop thru all bonds attached to the end of the bond 525 if (_notVisited[b->GetIdx()]) { // Don't revisit the initial bond 526 _queue.push(&(*b)); 527 _depth[b->GetIdx()] = 2; 528 _notVisited.SetBitOff(b->GetIdx()); 529 } 530 } 531 } 532 OBMolBondBFSIter(const OBMolBondBFSIter & ai)533 OBMolBondBFSIter::OBMolBondBFSIter(const OBMolBondBFSIter &ai) 534 { 535 _parent = ai._parent; 536 _ptr = ai._ptr; 537 _notVisited = ai._notVisited; 538 _queue = ai._queue; 539 _depth = ai._depth; 540 } 541 operator =(const OBMolBondBFSIter & ai)542 OBMolBondBFSIter& OBMolBondBFSIter::operator=(const OBMolBondBFSIter &ai) 543 { 544 if (this != &ai) 545 { 546 _parent = ai._parent; 547 _ptr = ai._ptr; 548 _notVisited = ai._notVisited; 549 _queue = ai._queue; 550 _depth = ai._depth; 551 } 552 return *this; 553 } 554 operator ++()555 OBMolBondBFSIter& OBMolBondBFSIter::operator++() 556 { 557 if (!_queue.empty()) 558 { 559 _ptr = _queue.front(); 560 _queue.pop(); 561 } 562 else // are there any disconnected subgraphs? 563 { 564 int next = _notVisited.FirstBit(); 565 if (next != _notVisited.EndBit()) 566 { 567 _ptr = _parent->GetBond(next + 1); // Bond index issue 568 if (_ptr != nullptr) 569 _depth[_ptr->GetIdx()] = 1; // new island 570 _notVisited.SetBitOff(next); 571 } 572 else 573 _ptr = nullptr; 574 } 575 576 if (_ptr) { 577 for( OBAtomBondIter b(_ptr->GetBeginAtom()); b; ++b ) 578 { // Loop thru all bonds attached to the start of the bond 579 if (_notVisited[b->GetIdx()]) { 580 _queue.push(&(*b)); 581 _depth[b->GetIdx()] = 2; 582 _notVisited.SetBitOff(b->GetIdx()); 583 } 584 } 585 for( OBAtomBondIter b(_ptr->GetEndAtom()); b; ++b ) 586 { // Loop thru all bonds attached to the end of the bond 587 if (_notVisited[b->GetIdx()]) { 588 _queue.push(&(*b)); 589 _depth[b->GetIdx()] = 2; 590 _notVisited.SetBitOff(b->GetIdx()); 591 } 592 } 593 } 594 return *this; 595 } 596 operator ++(int)597 OBMolBondBFSIter OBMolBondBFSIter::operator++(int) 598 { 599 OBMolBondBFSIter tmp(*this); 600 operator++(); 601 return tmp; 602 } 603 CurrentDepth() const604 int OBMolBondBFSIter::CurrentDepth() const 605 { 606 if (_ptr == nullptr) 607 return 0; 608 609 return _depth[_ptr->GetIdx()]; 610 } 611 /////////////////////////////////////////////////////////////////////// 612 613 /** \class OBMolBondIter obiter.h <openbabel/obiter.h> 614 615 To facilitate iteration through all bonds in a molecule, without resorting 616 to bond indexes (which may change in the future), a variety of 617 iterators are provided. 618 619 This has been made significantly easier by a series of macros in the 620 obiter.h header file: 621 622 \code 623 \#define FOR_BONDS_OF_MOL(b,m) for( OBMolBondIter b(m); b; ++b ) 624 \endcode 625 626 Here is an example: 627 \code 628 #include <openbabel/obiter.h> 629 #include <openbabel/mol.h> 630 631 OpenBabel::OBMol mol; 632 unsigned int bondOrderSum = 0; 633 FOR_BONDS_OF_MOL(b, mol) 634 { 635 // The variable b behaves like OBBond* when used with -> and * but 636 // but needs to be explicitly converted when appearing as a parameter 637 // in a function call - use &*b 638 bondOrderSum += b->GetBondOrder(); 639 } 640 \endcode 641 **/ 642 OBMolBondIter(OBMol * mol)643 OBMolBondIter::OBMolBondIter(OBMol *mol) 644 { 645 _parent = mol; 646 _ptr = _parent->BeginBond(_i); 647 } 648 OBMolBondIter(OBMol & mol)649 OBMolBondIter::OBMolBondIter(OBMol &mol) 650 { 651 _parent = &mol; 652 _ptr = _parent->BeginBond(_i); 653 } 654 OBMolBondIter(const OBMolBondIter & bi)655 OBMolBondIter::OBMolBondIter(const OBMolBondIter &bi) 656 { 657 _parent = bi._parent; 658 _ptr = bi._ptr; 659 _i = bi._i; 660 } 661 operator =(const OBMolBondIter & bi)662 OBMolBondIter& OBMolBondIter::operator=(const OBMolBondIter &bi) 663 { 664 if (this != &bi) 665 { 666 _parent = bi._parent; 667 _ptr = bi._ptr; 668 _i = bi._i; 669 } 670 return *this; 671 } 672 operator ++()673 OBMolBondIter& OBMolBondIter::operator++() 674 { 675 _ptr = _parent->NextBond(_i); 676 return *this; 677 } 678 operator ++(int)679 OBMolBondIter OBMolBondIter::operator++(int) 680 { 681 OBMolBondIter tmp(*this); 682 operator++(); 683 return tmp; 684 } 685 686 /** \class OBAtomAtomIter obiter.h <openbabel/obiter.h> 687 688 To facilitate iteration through all neighbors of an atom, without resorting 689 to bond indexes (which may change in the future), a variety of 690 iterator classes and methods are provided. 691 692 This has been made significantly easier by a series of macros in the 693 obiter.h header file: 694 695 \code 696 \#define FOR_NBORS_OF_ATOM(a,p) for( OBAtomAtomIter a(p); a; ++a ) 697 \endcode 698 699 Here is an example: 700 \code 701 #include <openbabel/obiter.h> 702 #include <openbabel/mol.h> 703 704 OpenBabel::OBMol mol; 705 FOR_ATOMS_OF_MOL(a, mol) 706 { 707 // The variable a behaves like OBAtom* when used with -> and * but 708 // but needs to be explicitly converted when appearing as a parameter 709 // in a function call - use &*a 710 FOR_NBORS_OF_ATOM(b, &*a) 711 { 712 ... 713 } 714 } 715 \endcode 716 **/ 717 OBAtomAtomIter(OBAtom * atm)718 OBAtomAtomIter::OBAtomAtomIter(OBAtom *atm) 719 { 720 _parent = atm; 721 _ptr = _parent->BeginNbrAtom(_i); 722 } 723 OBAtomAtomIter(OBAtom & atm)724 OBAtomAtomIter::OBAtomAtomIter(OBAtom &atm) 725 { 726 _parent = &atm; 727 _ptr = _parent->BeginNbrAtom(_i); 728 } 729 OBAtomAtomIter(const OBAtomAtomIter & ai)730 OBAtomAtomIter::OBAtomAtomIter(const OBAtomAtomIter &ai) 731 { 732 _parent = ai._parent; 733 _ptr = ai._ptr; 734 _i = ai._i; 735 } 736 operator =(const OBAtomAtomIter & ai)737 OBAtomAtomIter& OBAtomAtomIter::operator=(const OBAtomAtomIter &ai) 738 { 739 if (this != &ai) 740 { 741 _parent = ai._parent; 742 _ptr = ai._ptr; 743 _i = ai._i; 744 } 745 return *this; 746 } 747 operator ++()748 OBAtomAtomIter& OBAtomAtomIter::operator++() 749 { 750 _ptr = _parent->NextNbrAtom(_i); 751 return *this; 752 } 753 operator ++(int)754 OBAtomAtomIter OBAtomAtomIter::operator++(int) 755 { 756 OBAtomAtomIter tmp(*this); 757 operator++(); 758 return tmp; 759 } 760 761 /** \class OBAtomBondIter obiter.h <openbabel/obiter.h> 762 763 To facilitate iteration through all bonds on an atom, without resorting 764 to bond indexes (which may change in the future) a variety of 765 iterator classes and methods are provided. 766 767 This has been made significantly easier by a series of macros in the 768 obiter.h header file: 769 770 \code 771 \#define FOR_BONDS_OF_ATOM(b,p) for( OBAtomBondIter b(p); b; ++b ) 772 \endcode 773 774 Here is an example: 775 \code 776 #include <openbabel/obiter.h> 777 #include <openbabel/mol.h> 778 779 OpenBabel::OBAtom atom; 780 unsigned int tripleBondCount; 781 FOR_BONDS_OF_ATOM(b, atom) 782 { 783 // The variable b behaves like OBBond* when used with -> and * but 784 // but needs to be explicitly converted when appearing as a parameter 785 // in a function call - use &*b 786 if (b->GetBondOrder() == 3) 787 tripleBondCount++; 788 } 789 \endcode 790 **/ 791 OBAtomBondIter(OBAtom * atm)792 OBAtomBondIter::OBAtomBondIter(OBAtom *atm) 793 { 794 _parent = atm; 795 _ptr = _parent->BeginBond(_i); 796 } 797 OBAtomBondIter(OBAtom & atm)798 OBAtomBondIter::OBAtomBondIter(OBAtom &atm) 799 { 800 _parent = &atm; 801 _ptr = _parent->BeginBond(_i); 802 } 803 OBAtomBondIter(const OBAtomBondIter & bi)804 OBAtomBondIter::OBAtomBondIter(const OBAtomBondIter &bi) 805 { 806 _parent = bi._parent; 807 _ptr = bi._ptr; 808 _i = bi._i; 809 } 810 operator =(const OBAtomBondIter & bi)811 OBAtomBondIter& OBAtomBondIter::operator=(const OBAtomBondIter &bi) 812 { 813 if (this != &bi) 814 { 815 _parent = bi._parent; 816 _ptr = bi._ptr; 817 _i = bi._i; 818 } 819 return *this; 820 } 821 operator ++()822 OBAtomBondIter& OBAtomBondIter::operator++() 823 { 824 _ptr = _parent->NextBond(_i); 825 return *this; 826 } 827 operator ++(int)828 OBAtomBondIter OBAtomBondIter::operator++(int) 829 { 830 OBAtomBondIter tmp(*this); 831 operator++(); 832 return tmp; 833 } 834 835 /** \class OBResidueIter obiter.h <openbabel/obiter.h> 836 837 To facilitate iteration through all residues in a molecule, without resorting 838 to residue indexes (which may change in the future) a variety of 839 iterator classes and methods are provided. 840 841 This has been made significantly easier by a series of macros in the 842 obiter.h header file: 843 844 \code 845 \#define FOR_RESIDUES_OF_MOL(r,m) for( OBResidueIter r(m); r; ++r ) 846 \endcode 847 848 Here is an example: 849 \code 850 #include <openbabel/obiter.h> 851 #include <openbabel/mol.h> 852 853 OpenBabel::OBMol mol; 854 FOR_RESIDUES_OF_MOL(r, mol) 855 { 856 // The variable r behaves like OBResidue* when used with -> and * but 857 // but needs to be explicitly converted when appearing as a parameter 858 // in a function call - use &*r 859 860 if (r->GetName() == resname && r->GetNum() == rnum) 861 { 862 // got a match, let's go to work 863 ... 864 } 865 } 866 \endcode 867 **/ 868 OBResidueIter(OBMol * mol)869 OBResidueIter::OBResidueIter(OBMol *mol) 870 { 871 _parent = mol; 872 _ptr = _parent->BeginResidue(_i); 873 } 874 OBResidueIter(OBMol & mol)875 OBResidueIter::OBResidueIter(OBMol &mol) 876 { 877 _parent = &mol; 878 _ptr = _parent->BeginResidue(_i); 879 } 880 OBResidueIter(const OBResidueIter & ri)881 OBResidueIter::OBResidueIter(const OBResidueIter &ri) 882 { 883 _parent = ri._parent; 884 _ptr = ri._ptr; 885 _i = ri._i; 886 } 887 operator =(const OBResidueIter & ri)888 OBResidueIter& OBResidueIter::operator=(const OBResidueIter &ri) 889 { 890 if (this != &ri) 891 { 892 _parent = ri._parent; 893 _ptr = ri._ptr; 894 _i = ri._i; 895 } 896 return *this; 897 } 898 operator ++()899 OBResidueIter& OBResidueIter::operator++() 900 { 901 _ptr = _parent->NextResidue(_i); 902 return *this; 903 } 904 operator ++(int)905 OBResidueIter OBResidueIter::operator++(int) 906 { 907 OBResidueIter tmp(*this); 908 operator++(); 909 return tmp; 910 } 911 912 /** \class OBResidueAtomIter obiter.h <openbabel/obiter.h> 913 914 To facilitate iteration through all atoms in a residue, without resorting 915 to atom indexes (which may change in the future) a variety of 916 iterator classes and methods are provided. 917 918 This has been made significantly easier by a series of macros in the 919 obiter.h header file: 920 921 \code 922 \#define FOR_ATOMS_OF_RESIDUE(a,r) for( OBResidueAtomIter a(r); a; ++a ) 923 \endcode 924 925 Here is an example: 926 \code 927 #include <openbabel/obiter.h> 928 #include <openbabel/mol.h> 929 930 OpenBabel::OBMol mol; 931 double residueMass = 0.0; 932 FOR_RESIDUES_OF_MOL(r, mol) 933 { 934 // The variable r behaves like OBResidue* when used with -> and * but 935 // but needs to be explicitly converted when appearing as a parameter 936 // in a function call - use &*r 937 938 if (r->GetName() == resname && r->GetNum() == rnum) 939 { 940 FOR_ATOMS_OF_RESIDUE(a, &*r) 941 { 942 residueMass += a->GetMass(); 943 } 944 } 945 } 946 \endcode 947 **/ 948 OBResidueAtomIter(OBResidue * res)949 OBResidueAtomIter::OBResidueAtomIter(OBResidue *res): 950 _parent(res), _ptr(_parent->BeginAtom(_i)) 951 { } 952 OBResidueAtomIter(OBResidue & res)953 OBResidueAtomIter::OBResidueAtomIter(OBResidue &res): 954 _parent(&res), _ptr(_parent->BeginAtom(_i)) 955 { } 956 OBResidueAtomIter(const OBResidueAtomIter & ri)957 OBResidueAtomIter::OBResidueAtomIter(const OBResidueAtomIter &ri) 958 { 959 _parent = ri._parent; 960 _ptr = ri._ptr; 961 _i = ri._i; 962 } 963 operator =(const OBResidueAtomIter & ri)964 OBResidueAtomIter & OBResidueAtomIter::operator = (const OBResidueAtomIter &ri) 965 { 966 if (this != &ri) 967 { 968 _parent = ri._parent; 969 _ptr = ri._ptr; 970 _i = ri._i; 971 } 972 973 return (*this); 974 } 975 operator ++()976 OBResidueAtomIter& OBResidueAtomIter::operator++ () 977 { 978 _ptr = _parent->NextAtom(_i); 979 return (*this); 980 } 981 operator ++(int)982 OBResidueAtomIter OBResidueAtomIter::operator++ (int) 983 { 984 OBResidueAtomIter tmp(*this); 985 operator++(); 986 return tmp; 987 } 988 989 /** \class OBMolRingIter obiter.h <openbabel/obiter.h> 990 991 \since version 2.1 992 993 To facilitate iteration through all rings in a molecule, without resorting 994 to ring indexes (which may change in the future) a variety of 995 iterator classes and methods are provided. One word of warning is that 996 these iterator methods automatically call OBMol::FindSSSR() which may 997 involve a significant performance hit on large molecules. 998 999 Calling iterator classes has been made significantly easier by a series 1000 of macros in the obiter.h header file: 1001 1002 \code 1003 \#define FOR_RINGS_OF_MOL(r,m) for( OBMolRingIter r(m); r; ++r ) 1004 \endcode 1005 1006 Here is an example: 1007 \code 1008 #include <openbabel/obiter.h> 1009 #include <openbabel/mol.h> 1010 1011 OpenBabel::OBMol mol; 1012 FOR_RINGS_OF_MOL(r, mol) 1013 { 1014 // The variable r behaves like OBRing* when used with -> and * but 1015 // but needs to be explicitly converted when appearing as a parameter 1016 // in a function call - use &*r 1017 1018 } 1019 \endcode 1020 **/ 1021 OBMolRingIter(OBMol * mol)1022 OBMolRingIter::OBMolRingIter(OBMol *mol): _parent(mol) 1023 { 1024 if (!_parent->HasSSSRPerceived()) 1025 _parent->FindSSSR(); 1026 1027 _rings = (OBRingData *) _parent->GetData("SSSR"); 1028 if(_rings) 1029 _ptr = _rings->BeginRing(_i); 1030 } 1031 OBMolRingIter(OBMol & mol)1032 OBMolRingIter::OBMolRingIter(OBMol &mol): _parent(&mol) 1033 { 1034 if (!_parent->HasSSSRPerceived()) 1035 _parent->FindSSSR(); 1036 1037 _rings = (OBRingData *) _parent->GetData("SSSR"); 1038 if (_rings) 1039 _ptr = _rings->BeginRing(_i); 1040 } 1041 OBMolRingIter(const OBMolRingIter & ri)1042 OBMolRingIter::OBMolRingIter(const OBMolRingIter &ri) 1043 { 1044 _parent = ri._parent; 1045 _ptr = ri._ptr; 1046 _rings = ri._rings; 1047 _i = ri._i; 1048 } 1049 operator =(const OBMolRingIter & ri)1050 OBMolRingIter& OBMolRingIter::operator=(const OBMolRingIter &ri) 1051 { 1052 if (this != &ri) 1053 { 1054 _parent = ri._parent; 1055 _ptr = ri._ptr; 1056 _rings = ri._rings; 1057 _i = ri._i; 1058 } 1059 return *this; 1060 } 1061 operator ++()1062 OBMolRingIter& OBMolRingIter::operator++() 1063 { 1064 if (_rings) 1065 _ptr = _rings->NextRing(_i); 1066 return *this; 1067 } 1068 operator ++(int)1069 OBMolRingIter OBMolRingIter::operator++(int) 1070 { 1071 OBMolRingIter tmp(*this); 1072 operator++(); 1073 return tmp; 1074 } 1075 1076 /** \class OBMolAngleIter obiter.h <openbabel/obiter.h> 1077 1078 \since version 2.1 1079 1080 To facilitate iteration through all angles in a molecule, without resorting 1081 to atom indexes (which <strong>will</strong> change in the future), a 1082 variety of iterator methods are provided. 1083 1084 This has been made significantly easier by a series of macros in the 1085 obiter.h header file: 1086 1087 \code 1088 \#define FOR_ANGLES_OF_MOL(a,m) for( OBMolAngleIter a(m); a; a++ ) 1089 \endcode 1090 1091 Here is an example: 1092 \code 1093 #include <openbabel/obiter.h> 1094 #include <openbabel/mol.h> 1095 1096 OpenBabel::OBMol mol; 1097 OpenBabel::OBAtom *a, *b, *c; 1098 double ang; 1099 1100 FOR_ANGLES_OF_MOL(angle, mol) 1101 { 1102 // The variable a behaves like OBAngle* when used with -> and * but 1103 // but needs to be explicitly converted when appearing as a parameter 1104 // in a function call - use &*a 1105 1106 b = _mol.GetAtom((*angle)[0] + 1); 1107 a = _mol.GetAtom((*angle)[1] + 1); 1108 c = _mol.GetAtom((*angle)[2] + 1); 1109 ang = a->GetAngle(b->GetIdx(), c->GetIdx()); 1110 } 1111 \endcode 1112 **/ 1113 OBMolAngleIter(OBMol * mol)1114 OBMolAngleIter::OBMolAngleIter(OBMol *mol) 1115 { 1116 mol->FindAngles(); 1117 OBAngleData *ad = (OBAngleData *) mol->GetData(OBGenericDataType::AngleData); 1118 ad->FillAngleArray(_vangle); 1119 1120 _parent = mol; 1121 if (!_vangle.empty()) { 1122 _i = _vangle.begin(); 1123 _angle = *_i; 1124 } else { 1125 _i = _vangle.end(); 1126 } 1127 } 1128 OBMolAngleIter(OBMol & mol)1129 OBMolAngleIter::OBMolAngleIter(OBMol &mol) 1130 { 1131 mol.FindAngles(); 1132 OBAngleData *ad = (OBAngleData *) mol.GetData(OBGenericDataType::AngleData); 1133 ad->FillAngleArray(_vangle); 1134 1135 _parent = &mol; 1136 if (!_vangle.empty()) { 1137 _i = _vangle.begin(); 1138 _angle = *_i; 1139 } else { 1140 _i = _vangle.end(); 1141 } 1142 } 1143 OBMolAngleIter(const OBMolAngleIter & ai)1144 OBMolAngleIter::OBMolAngleIter(const OBMolAngleIter &ai) 1145 { 1146 _parent = ai._parent; 1147 _angle = ai._angle; 1148 _vangle = ai._vangle; 1149 _i = ai._i; 1150 } 1151 operator =(const OBMolAngleIter & ai)1152 OBMolAngleIter& OBMolAngleIter::operator=(const OBMolAngleIter &ai) 1153 { 1154 if (this != &ai) 1155 { 1156 _parent = ai._parent; 1157 _angle = ai._angle; 1158 _vangle = ai._vangle; 1159 _i = ai._i; 1160 } 1161 return *this; 1162 } 1163 operator ++()1164 OBMolAngleIter& OBMolAngleIter::operator++() 1165 { 1166 _i++; 1167 1168 if (_i != _vangle.end()) 1169 _angle = *_i; 1170 1171 return *this; 1172 } 1173 1174 /** \class OBMolTorsionIter obiter.h <openbabel/obiter.h> 1175 1176 \since version 2.1 1177 1178 To facilitate iteration through all torsions in a molecule, without resorting 1179 to atom indexes (which <strong>will</strong> change in the future), a 1180 variety of iterator methods are provided. 1181 1182 This has been made significantly easier by a series of macros in the 1183 obiter.h header file: 1184 1185 \code 1186 \#define FOR_TORSIONS_OF_MOL(t,m) for( OBMolTorsionIter t(m); t; t++ ) 1187 \endcode 1188 1189 Here is an example: 1190 \code 1191 #include <openbabel/obiter.h> 1192 #include <openbabel/mol.h> 1193 1194 OpenBabel::OBMol mol; 1195 OpenBabel::OBAtom *a, *b, *c, *d; 1196 double tor; 1197 1198 FOR_TORSIONS_OF_MOL(t, mol) 1199 { 1200 // The variable a behaves like OBTorsion* when used with -> and * but 1201 // but needs to be explicitly converted when appearing as a parameter 1202 // in a function call - use &*t 1203 1204 a = _mol.GetAtom((*t)[0] + 1); // indices in vector start from 0!!! 1205 b = _mol.GetAtom((*t)[1] + 1); 1206 c = _mol.GetAtom((*t)[2] + 1); 1207 d = _mol.GetAtom((*t)[3] + 1); 1208 tor = mol.GetTorsion(a->GetIdx(), b->GetIdx(), c->GetIdx(), d->GetIdx()); 1209 } 1210 \endcode 1211 **/ 1212 OBMolTorsionIter(OBMol * mol)1213 OBMolTorsionIter::OBMolTorsionIter(OBMol *mol) 1214 { 1215 mol->FindTorsions(); 1216 OBTorsionData *td = (OBTorsionData *) mol->GetData(OBGenericDataType::TorsionData); 1217 td->FillTorsionArray(_vtorsion); 1218 1219 _parent = mol; 1220 if (!_vtorsion.empty()) { 1221 _i = _vtorsion.begin(); 1222 _torsion = *_i; 1223 } else { 1224 _i = _vtorsion.end(); 1225 } 1226 } 1227 OBMolTorsionIter(OBMol & mol)1228 OBMolTorsionIter::OBMolTorsionIter(OBMol &mol) 1229 { 1230 mol.FindTorsions(); 1231 OBTorsionData *td = (OBTorsionData *) mol.GetData(OBGenericDataType::TorsionData); 1232 td->FillTorsionArray(_vtorsion); 1233 1234 _parent = &mol; 1235 if (!_vtorsion.empty()) { 1236 _i = _vtorsion.begin(); 1237 _torsion = *_i; 1238 } else { 1239 // Avogadro bug #1972244 1240 // always set _i, _i will be compared to _vtorsion.end() in OBMolTorsionIter::bool() 1241 _i = _vtorsion.end(); 1242 } 1243 } 1244 OBMolTorsionIter(const OBMolTorsionIter & ai)1245 OBMolTorsionIter::OBMolTorsionIter(const OBMolTorsionIter &ai) 1246 { 1247 _parent = ai._parent; 1248 _torsion = ai._torsion; 1249 _vtorsion = ai._vtorsion; 1250 _i = ai._i; 1251 } 1252 operator =(const OBMolTorsionIter & ai)1253 OBMolTorsionIter& OBMolTorsionIter::operator=(const OBMolTorsionIter &ai) 1254 { 1255 if (this != &ai) 1256 { 1257 _parent = ai._parent; 1258 _torsion = ai._torsion; 1259 _vtorsion = ai._vtorsion; 1260 _i = ai._i; 1261 } 1262 return *this; 1263 } 1264 operator ++()1265 OBMolTorsionIter& OBMolTorsionIter::operator++() 1266 { 1267 _i++; 1268 1269 if (_i != _vtorsion.end()) 1270 _torsion = *_i; 1271 1272 return *this; 1273 } 1274 1275 /** \class OBMolPairIter obiter.h <openbabel/obiter.h> 1276 1277 \since version 2.1. 1278 1279 To facilitate iteration through all pairs of atoms in a molecule, without 1280 resorting to bond indexes (which may change in the future), a variety of 1281 iterators are provided. These pairs of atoms are separated by 4 atoms 1282 or more (i.e., these are non-bonded interactions). 1283 1284 This has been made significantly easier by a series of macros in the 1285 obiter.h header file: 1286 1287 \code 1288 \#define FOR_PAIRS_OF_MOL(p,m) for( OBMolPairIter p(m); p; p++ ) 1289 \endcode 1290 1291 Here is an example: 1292 \code 1293 #include <openbabel/obiter.h> 1294 #include <openbabel/mol.h> 1295 1296 OpenBabel::OBMol mol; 1297 OpenBabel::OBAtom *a, *b; 1298 double rab; 1299 1300 FOR_PAIRS_OF_MOL(p, mol) 1301 { 1302 // The variable b behaves like OBBond* when used with -> and * but 1303 // but needs to be explicitly converted when appearing as a parameter 1304 // in a function call - use &*p 1305 1306 a = mol.GetAtom(p->first); 1307 b = mol.GetAtom(p->second); 1308 rab = a->GetDistance(b); 1309 } 1310 \endcode 1311 **/ 1312 OBMolPairIter(OBMol * mol)1313 OBMolPairIter::OBMolPairIter(OBMol *mol) 1314 { 1315 _parent = mol; 1316 1317 bool foundPair = false; 1318 OBAtom *a = _parent->BeginAtom(_i); 1319 if (!a) 1320 return; 1321 OBAtom *b = _parent->BeginAtom(_j); 1322 while (!foundPair) { 1323 b = _parent->NextAtom(_j); 1324 1325 if (!b) { 1326 a = _parent->NextAtom(_i); 1327 if (!a) 1328 return; 1329 b = _parent->BeginAtom(_j); 1330 } 1331 1332 if (a->GetIdx() >= b->GetIdx()) continue; 1333 if (a->IsConnected(b)) continue; 1334 if (a->IsOneThree(b)) continue; 1335 1336 foundPair = true; 1337 } 1338 1339 _pair.clear(); 1340 _pair.push_back(a->GetIdx()); 1341 _pair.push_back(b->GetIdx()); 1342 } 1343 OBMolPairIter(OBMol & mol)1344 OBMolPairIter::OBMolPairIter(OBMol &mol) 1345 { 1346 _parent = &mol; 1347 1348 bool foundPair = false; 1349 OBAtom *a = _parent->BeginAtom(_i); 1350 if (!a) 1351 return; 1352 OBAtom *b = _parent->BeginAtom(_j); 1353 while (!foundPair) { 1354 b = _parent->NextAtom(_j); 1355 1356 if (!b) { 1357 a = _parent->NextAtom(_i); 1358 if (!a) 1359 return; 1360 b = _parent->BeginAtom(_j); 1361 } 1362 1363 if (a->GetIdx() >= b->GetIdx()) continue; 1364 if (a->IsConnected(b)) continue; 1365 if (a->IsOneThree(b)) continue; 1366 1367 foundPair = true; 1368 } 1369 1370 _pair.clear(); 1371 _pair.push_back(a->GetIdx()); 1372 _pair.push_back(b->GetIdx()); 1373 } 1374 OBMolPairIter(const OBMolPairIter & ai)1375 OBMolPairIter::OBMolPairIter(const OBMolPairIter &ai) 1376 { 1377 _parent = ai._parent; 1378 _pair = ai._pair; 1379 _i = ai._i; 1380 _j = ai._j; 1381 } 1382 operator =(const OBMolPairIter & ai)1383 OBMolPairIter& OBMolPairIter::operator=(const OBMolPairIter &ai) 1384 { 1385 if (this != &ai) { 1386 _parent = ai._parent; 1387 _pair = ai._pair; 1388 _i = ai._i; 1389 _j = ai._j; 1390 } 1391 return *this; 1392 } 1393 operator ++()1394 OBMolPairIter& OBMolPairIter::operator++() 1395 { 1396 _pair.clear(); 1397 1398 bool foundPair = false; 1399 OBAtom *a, *b; 1400 a = *_i; 1401 while (!foundPair) { 1402 b = _parent->NextAtom(_j); 1403 1404 if (!b) { 1405 a = _parent->NextAtom(_i); 1406 if (!a) 1407 return *this; 1408 b = _parent->BeginAtom(_j); 1409 } 1410 1411 if (a->GetIdx() >= b->GetIdx()) continue; 1412 if (a->IsConnected(b)) continue; 1413 if (a->IsOneThree(b)) continue; 1414 1415 1416 foundPair = true; 1417 } 1418 1419 _pair.push_back(a->GetIdx()); 1420 _pair.push_back(b->GetIdx()); 1421 1422 return *this; 1423 } 1424 1425 } // namespace OpenBabel 1426 1427 //! \file obiter.cpp 1428 //! \brief STL-style iterators for Open Babel. 1429