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