ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/obatom.cpp
Revision: 2466
Committed: Wed Nov 23 01:05:59 2005 UTC (18 years, 7 months ago) by chuckv
File size: 43115 byte(s)
Log Message:
Changed file names that conflict w/ oopse file name object files.

File Contents

# User Rev Content
1 chuckv 2466 /**********************************************************************
2     atom.cpp - Handle OBAtom class.
3    
4     Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5     Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
6     Some portions Copyright (C) 2003 by Michael Banck
7    
8     This file is part of the Open Babel project.
9     For more information, see <http://openbabel.sourceforge.net/>
10    
11     This program is free software; you can redistribute it and/or modify
12     it under the terms of the GNU General Public License as published by
13     the Free Software Foundation version 2 of the License.
14    
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     GNU General Public License for more details.
19     ***********************************************************************/
20    
21     #include "mol.hpp"
22     #include "typer.hpp"
23     #include "molchrg.hpp"
24     #include "phmodel.hpp"
25    
26     #include "matrix3x3.hpp"
27    
28     #if !HAVE_STRNCASECMP
29     extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
30     #endif
31    
32     using namespace std;
33    
34     namespace OpenBabel
35     {
36    
37     /** \class OBAtom
38     \brief Atom class
39    
40     To understand the OBAtom class it is important to state a key
41     decision on which the design was based. In OBabel the atom class
42     existed, but it was only a data container. All data access and
43     modification of atoms was done through the molecule. The result
44     was a molecule class that was very large an unwieldy. So the OBAtom
45     class was made smarter, and many of the atom-specific routines
46     were separated into the OBAtom thereby decentralizing and
47     shrinking the OBMol class. As a result the OBAtom class not only
48     holds data, but facilitates extraction of data perceived from both
49     the atom and the molecule.
50    
51     A number of data extraction methods perform what is called
52     <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">`Lazy Evaluation,'</a> which is essentially on-the-fly evaluation.
53     For example, when an atom is queried as to whether it is cyclic
54     or what it's hybridization state is the information is perceived
55     automatically. The perception of a particular trait is actually
56     performed on the entire molecule the first time it is requested of
57     an atom or bond, and stored for subsequent requests for the same
58     trait of additional atoms or bonds.The OBAtom class is similar to
59     OBMol and the whole of Open Babel in that data access and modification
60     is done through Get and Set methods.
61    
62     The following code demonstrates how to print out the atom numbers,
63     element numbers, and coordinates of a molecule:
64     \code
65     OBMol mol;
66    
67     FOR_ATOMS_IN_MOL(atom, mol)
68     {
69     cout << atom->GetIdx() << ` `;
70     cout << atom->GetAtomicNum() << ` `;
71     cout << atom->GetVector() << endl;
72     }
73     \endcode
74     A number of the property member functions indicate that atoms
75     have some knowlege of their covalently attached neighbor atoms.
76     Bonding information is partly redundant within a molecule in
77     that an OBMol has a complete list of bonds in a molecule, and
78     an OBAtom has a list bonds of which it is a member. The following
79     code demonstrates how an OBAtom uses its bond information to loop
80     over atoms attached to itself:
81     \code
82     OBMol mol;
83     OBAtom *atom;
84    
85     atom = mol.GetAtom(1);
86     FOR_NBORS_OF_ATOM(nbr, atom)
87     {
88     cout << "atom #" << atom->GetIdx() << " is attached to atom #" << nbr->GetIdx() << endl;
89     }
90     \endcode
91    
92     should produce an output like
93     \code
94     atom #1 is attached to atom #2
95     \endcode
96     */
97    
98     extern OBAromaticTyper aromtyper;
99     extern OBAtomTyper atomtyper;
100     extern OBPhModel phmodel;
101    
102     //
103     // OBAtom member functions
104     //
105    
106     OBAtom::OBAtom()
107     {
108     _parent = (OBMol*)NULL;
109     Clear();
110     }
111    
112     OBAtom::~OBAtom()
113     {
114     if (_residue != NULL)
115     _residue->RemoveAtom(this);
116     if (!_vdata.empty())
117     {
118     vector<OBGenericData*>::iterator m;
119     for (m = _vdata.begin();m != _vdata.end();m++)
120     delete *m;
121     _vdata.clear();
122     }
123     }
124    
125     void OBAtom::Clear()
126     {
127     _c = (double**)NULL;
128     _cidx = 0;
129     _flags=0;
130     _idx = 0;
131     _hyb = 0;
132     _ele = (char)0;
133     _isotope = 0;
134     _spinmultiplicity=0; // CM 18 Sept 2003
135     _impval = 0;
136     _fcharge = 0;
137     _type[0] = '\0';
138     _pcharge = 0.0;
139     _vbond.clear();
140     _vbond.reserve(4);
141     _residue = (OBResidue*)NULL;
142     _vdata.clear();
143     }
144    
145     OBAtom &OBAtom::operator=(OBAtom &src)
146     //copy atom information
147     //bond info is not copied here as ptrs may be invalid
148     //vdata is also not copied yet (again it's unclear what can work)
149     {
150     _idx = src.GetIdx();
151     _hyb = src.GetHyb();
152     _ele = src.GetAtomicNum();
153     _isotope = src.GetIsotope();
154     _fcharge = src.GetFormalCharge();
155     _spinmultiplicity = src.GetSpinMultiplicity();
156     strcpy(_type,src.GetType());
157     _pcharge = src.GetPartialCharge();
158     _v = src.GetVector();
159     _flags = src.GetFlag();
160     _residue = (OBResidue*)NULL;
161     return(*this);
162     }
163    
164     bool OBAtom::IsConnected(OBAtom *a1)
165     {
166     vector<OBEdgeBase*>::iterator i;
167     OBBond *bond;
168    
169     for (bond = BeginBond(i);bond;bond = NextBond(i))
170     if (bond->GetBeginAtom() == a1 || bond->GetEndAtom() == a1)
171     return(true);
172    
173     return(false);
174     }
175    
176     bool OBAtom::IsOneThree(OBAtom *a1)
177     {
178     OBAtom *atom1,*atom2;
179     OBBond *bond1,*bond2;
180     vector<OBEdgeBase*>::iterator i,j;
181     atom1 = this;
182     atom2 = a1;
183    
184     for (bond1 = atom1->BeginBond(i);bond1;bond1 = atom1->NextBond(i))
185     for (bond2 = atom2->BeginBond(j);bond2;bond2 = atom2->NextBond(j))
186     if (bond1->GetNbrAtom(atom1) == bond2->GetNbrAtom(atom2))
187     return(true);
188    
189     return(false);
190     }
191    
192     bool OBAtom::IsOneFour(OBAtom *a1)
193     {
194     OBAtom *atom1,*atom2;
195     OBBond *bond1,*bond2;
196     vector<OBEdgeBase*>::iterator i,j;
197     atom1 = this;
198     atom2 = a1;
199    
200     for (bond1 = atom1->BeginBond(i);bond1;bond1 = atom1->NextBond(i))
201     for (bond2 = atom2->BeginBond(j);bond2;bond2 = atom2->NextBond(j))
202     if ((bond1->GetNbrAtom(atom1))->IsConnected(bond2->GetNbrAtom(atom2)))
203     return(true);
204    
205     return(false);
206     }
207    
208     bool OBAtom::IsAxial()
209     {
210     double tor;
211     OBAtom *a,*b,*c;
212     vector<OBEdgeBase*>::iterator i,j,k;
213    
214     for (a = BeginNbrAtom(i);a;a = NextNbrAtom(i))
215     if (a->GetHyb() == 3 && a->IsInRing() && !(*i)->IsInRing())
216     for (b = a->BeginNbrAtom(j);b;b = a->NextNbrAtom(j))
217     if (b != this && b->IsInRing() && b->GetHyb() == 3)
218     for (c = b->BeginNbrAtom(k);c;c = b->NextNbrAtom(k))
219     if (c != a && c->IsInRing())
220     {
221     tor = fabs(((OBMol*)GetParent())->GetTorsion(this,a,b,c));
222     return(tor > 55.0 && tor < 75.0);
223     }
224    
225     return(false);
226     }
227    
228    
229     bool OBAtom::HasAlphaBetaUnsat(bool includePandS)
230     {
231     OBAtom *a1,*a2;
232     vector<OBEdgeBase*>::iterator i,j;
233    
234     for (a1 = BeginNbrAtom(i);a1;a1 = NextNbrAtom(i))
235     if (includePandS || (!a1->IsPhosphorus() && !a1->IsSulfur()))
236     for (a2 = a1->BeginNbrAtom(j);a2;a2 = a1->NextNbrAtom(j))
237     if (a2 != this && ((*j)->GetBO() == 2 || (*j)->GetBO() == 3 || (*j)->GetBO() == 5))
238     return(true);
239    
240     return(false);
241     }
242    
243     bool OBAtom::HasBondOfOrder(unsigned int order)
244     {
245     OBBond *bond;
246     vector<OBEdgeBase*>::iterator i;
247     for (bond = BeginBond(i);bond;bond = NextBond(i))
248     if (bond->GetBO() == order)
249     return(true);
250    
251     return(false);
252     }
253    
254     int OBAtom::CountBondsOfOrder(unsigned int order)
255     {
256     int count = 0;
257     OBBond *bond;
258     vector<OBEdgeBase*>::iterator i;
259     for (bond = BeginBond(i);bond;bond = NextBond(i))
260     if (bond->GetBO() == order)
261     count++;
262    
263     return(count);
264     }
265    
266     bool OBAtom::HasNonSingleBond()
267     {
268     OBBond *bond;
269     vector<OBEdgeBase*>::iterator i;
270     for (bond = BeginBond(i);bond;bond = NextBond(i))
271     if (bond->GetBO() != 1)
272     return(true);
273    
274     return(false);
275     }
276    
277     bool OBAtom::IsPolarHydrogen()
278     {
279     if (!IsHydrogen())
280     return(false);
281    
282     OBAtom *atom;
283     OBBond *bond;
284     vector<OBEdgeBase*>::iterator i;
285     for (bond = BeginBond(i);bond;bond = NextBond(i))
286     {
287     atom = bond->GetNbrAtom(this);
288     if (atom->GetAtomicNum() == 7)
289     return(true);
290     if (atom->GetAtomicNum() == 8)
291     return(true);
292     if (atom->GetAtomicNum() == 15)
293     return(true);
294     if (atom->GetAtomicNum() == 16)
295     return(true);
296     }
297    
298     return(false);
299     }
300    
301     bool OBAtom::IsNonPolarHydrogen()
302     {
303     if (!IsHydrogen())
304     return(false);
305    
306     OBAtom *atom;
307     OBBond *bond;
308     vector<OBEdgeBase*>::iterator i;
309     for (bond = BeginBond(i);bond;bond = NextBond(i))
310     {
311     atom = bond->GetNbrAtom(this);
312     if (atom->GetAtomicNum() == 6)
313     return(true);
314     }
315    
316     return(false);
317     }
318    
319     vector3 &OBAtom::GetVector()
320     {
321     if (!_c)
322     return(_v);
323    
324     _v.Set((*_c)[_cidx],(*_c)[_cidx+1],(*_c)[_cidx+2]);
325     return(_v);
326     }
327    
328     void OBAtom::SetVector()
329     {
330     // obAssert(_c);
331     if (_c)
332     _v.Set((*_c)[_cidx],(*_c)[_cidx+1],(*_c)[_cidx+2]);
333     }
334    
335     void OBAtom::SetVector(vector3 &v)
336     {
337     if (!_c)
338     _v = v;
339     else
340     {
341     (*_c)[_cidx ] = v.x();
342     (*_c)[_cidx+1] = v.y();
343     (*_c)[_cidx+2] = v.z();
344     }
345     }
346    
347     void OBAtom::SetVector(const double x,const double y,const double z)
348     {
349     if (!_c)
350     _v.Set(x,y,z);
351     else
352     {
353     (*_c)[_cidx ] = x;
354     (*_c)[_cidx+1] = y;
355     (*_c)[_cidx+2] = z;
356     }
357     }
358    
359     void OBAtom::SetType(char *type)
360     {
361     strcpy(_type,type);
362     if (_ele == 1 && type[0] == 'D')
363     _isotope = 2;
364     }
365    
366     void OBAtom::SetType(string &type)
367     {
368     strcpy(_type,type.c_str());
369     if (_ele == 1 && type[0] == 'D')
370     _isotope = 2;
371     }
372    
373     void OBAtom::SetIsotope(unsigned int iso)
374     {
375     if (_ele == 1 && iso == 2)
376     SetType("D");
377     else if (_ele == 1 && (iso == 1 || iso == 0))
378     SetType("H");
379    
380     _isotope = iso;
381     }
382    
383     OBAtom *OBAtom::GetNextAtom()
384     {
385     OBMol *mol = (OBMol*)GetParent();
386     return(((unsigned)GetIdx() == mol->NumAtoms())? NULL : mol->GetAtom(GetIdx()+1));
387     }
388    
389     OBResidue *OBAtom::GetResidue()
390     {
391     if (_residue != NULL)
392     return _residue;
393     else if (!((OBMol*)GetParent())->HasChainsPerceived())
394     {
395     chainsparser.PerceiveChains(*((OBMol*)GetParent()));
396     ((OBMol*)GetParent())->SetChainsPerceived();
397     return _residue;
398     }
399     else
400     return NULL;
401     }
402    
403     double OBAtom::GetAtomicMass() const
404     {
405     if (_isotope == 0)
406     return etab.GetMass(_ele);
407     else
408     return isotab.GetExactMass(_ele, _isotope);
409     }
410    
411     double OBAtom::GetExactMass() const
412     {
413     return isotab.GetExactMass(_ele, _isotope);
414     }
415    
416     char *OBAtom::GetType()
417     {
418     OBMol *mol = (OBMol*)GetParent();
419     if (mol && !mol->HasAtomTypesPerceived())
420     atomtyper.AssignTypes(*((OBMol*)GetParent()));
421    
422     if (strlen(_type) == 0) // Somehow we still don't have a type!
423     {
424     char num[6];
425     string fromType = ttab.GetFromType(); // save previous types
426     string toType = ttab.GetToType();
427    
428     ttab.SetFromType("ATN");
429     ttab.SetToType("INT");
430     snprintf(num, 6, "%d", GetAtomicNum());
431     ttab.Translate(_type, num);
432    
433     ttab.SetFromType(fromType.c_str());
434     ttab.SetToType(toType.c_str());
435     }
436     if (_ele == 1 && _isotope == 2)
437     snprintf(_type, 6, "%s", "D");
438    
439     return(_type);
440     }
441    
442     unsigned int OBAtom::GetImplicitValence() const
443     {
444     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
445     if (mol && !mol->HasImplicitValencePerceived())
446     atomtyper.AssignImplicitValence(*((OBMol*)((OBAtom*)this)->GetParent()));
447    
448     return((unsigned int)_impval);
449     }
450    
451     unsigned int OBAtom::GetHyb() const
452     {
453     //hybridization is assigned when atoms are typed
454     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
455     if (mol && !mol->HasHybridizationPerceived())
456     atomtyper.AssignHyb(*mol);
457    
458     return(_hyb);
459     }
460    
461    
462     unsigned int OBAtom::GetHvyValence() const
463     {
464     unsigned int count=0;
465    
466     OBBond *bond;
467     vector<OBEdgeBase*>::iterator i;
468     for (bond = ((OBAtom*)this)->BeginBond(i); bond; bond = ((OBAtom*)this)->NextBond(i))
469     if (!(bond->GetNbrAtom((OBAtom*)this)->IsHydrogen()))
470     count++;
471    
472     return(count);
473     }
474    
475     unsigned int OBAtom::GetHeteroValence() const
476     {
477     unsigned int count=0;
478     OBBond *bond;
479     vector<OBEdgeBase*>::iterator i;
480     for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
481     if (bond->GetNbrAtom((OBAtom*)this)->IsHeteroatom())
482     count++;
483    
484     return((unsigned int)count);
485     }
486    
487     double OBAtom::GetPartialCharge()
488     {
489     if (!GetParent())
490     return(_pcharge);
491     if (!((OBMol*)GetParent())->AutomaticPartialCharge())
492     return(_pcharge);
493    
494     if (!((OBMol*)GetParent())->HasPartialChargesPerceived())
495     {
496     //seed partial charges are set in the atom typing procedure
497     OBAtom *atom;
498     OBMol *mol = (OBMol*)GetParent();
499     vector<OBNodeBase*>::iterator i;
500     for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i))
501     atom->SetPartialCharge(0.0);
502    
503     phmodel.AssignSeedPartialCharge(*((OBMol*)GetParent()));
504     OBGastChrg gc;
505     gc.AssignPartialCharges(*((OBMol*)GetParent()));
506     }
507    
508     return(_pcharge);
509     }
510    
511     //! Returns true if nitrogen is part of an amide
512     bool OBAtom::IsAmideNitrogen()
513     {
514     if (!IsNitrogen())
515     return(false);
516    
517     OBAtom *nbratom,*atom;
518     OBBond *abbond,*bond;
519    
520     vector<OBEdgeBase*>::iterator i,j;
521     atom = this;
522     for (bond = BeginBond(i);bond;bond = NextBond(i))
523     {
524     nbratom = bond->GetNbrAtom(atom);
525     for (abbond = nbratom->BeginBond(j);abbond;abbond = nbratom->NextBond(j))
526     if (abbond->GetBO() == 2 &&
527     (((abbond->GetNbrAtom(nbratom))->GetAtomicNum() == 8) ||
528     ((abbond->GetNbrAtom(nbratom))->GetAtomicNum() == 16)))
529     return(true);
530     }
531    
532     return(false);
533     }
534    
535     bool OBAtom::IsAromaticNOxide()
536     {
537     if (!IsNitrogen() || !IsAromatic())
538     return(false);
539    
540     OBAtom *atom;
541     vector<OBEdgeBase*>::iterator i;
542    
543     for (atom = BeginNbrAtom(i);atom;atom = NextNbrAtom(i))
544     if (atom->IsOxygen() && !(*i)->IsInRing() && (*i)->GetBO() == 2)
545     return(true);
546    
547     return(false);
548     }
549    
550     bool OBAtom::IsCarboxylOxygen()
551     {
552     if (!IsOxygen())
553     return(false);
554     if (GetHvyValence() != 1)
555     return(false);
556    
557     OBAtom *atom;
558     OBBond *bond;
559     vector<OBEdgeBase*>::iterator i;
560    
561     atom = NULL;
562     for (bond = BeginBond(i);bond;bond = NextBond(i))
563     if ((bond->GetNbrAtom(this))->IsCarbon())
564     {
565     atom = bond->GetNbrAtom(this);
566     break;
567     }
568     if (!atom)
569     return(false);
570     if (atom->CountFreeOxygens() != 2)
571     return(false);
572    
573     //atom is connected to a carbon that has a total
574     //of 2 attached free oxygens
575     return(true);
576     }
577    
578     bool OBAtom::IsPhosphateOxygen()
579     {
580     if (!IsOxygen())
581     return(false);
582     if (GetHvyValence() != 1)
583     return(false);
584    
585     OBAtom *atom;
586     OBBond *bond;
587     vector<OBEdgeBase*>::iterator i;
588    
589     atom = NULL;
590     for (bond = BeginBond(i);bond;bond = NextBond(i))
591     if ((bond->GetNbrAtom(this))->IsPhosphorus())
592     {
593     atom = bond->GetNbrAtom(this);
594     break;
595     }
596     if (!atom)
597     return(false);
598     if (atom->CountFreeOxygens() > 2)
599     return(true);
600    
601     //atom is connected to a carbon that has a total
602     //of 2 attached free oxygens
603     return(false);
604     }
605    
606     bool OBAtom::IsSulfateOxygen()
607     {
608     if (!IsOxygen())
609     return(false);
610     if (GetHvyValence() != 1)
611     return(false);
612    
613     OBAtom *atom;
614     OBBond *bond;
615     vector<OBEdgeBase*>::iterator i;
616    
617     atom = NULL;
618     for (bond = BeginBond(i);bond;bond = NextBond(i))
619     if ((bond->GetNbrAtom(this))->IsSulfur())
620     {
621     atom = bond->GetNbrAtom(this);
622     break;
623     }
624     if (!atom)
625     return(false);
626     if (atom->CountFreeOxygens() < 3)
627     return(false);
628    
629     //atom is connected to a carbon that has a total
630     //of 2 attached free oxygens
631     return(true);
632     }
633    
634     bool OBAtom::IsNitroOxygen()
635     {
636     if (!IsOxygen())
637     return(false);
638     if (GetHvyValence() != 1)
639     return(false);
640    
641     OBAtom *atom;
642     OBBond *bond;
643     vector<OBEdgeBase*>::iterator i;
644    
645     atom = NULL;
646     for (bond = BeginBond(i);bond;bond = NextBond(i))
647     if ((bond->GetNbrAtom(this))->IsNitrogen())
648     {
649     atom = bond->GetNbrAtom(this);
650     break;
651     }
652     if (!atom)
653     return(false);
654     if (atom->CountFreeOxygens() != 2)
655     return(false);
656    
657     //atom is connected to a nitrogen that has a total
658     //of 2 attached free oxygens
659     return(true);
660     }
661    
662     bool OBAtom::IsHeteroatom()
663     {
664     switch(GetAtomicNum())
665     {
666     case 7:
667     case 8:
668     case 15:
669     case 16:
670     case 33:
671     case 34:
672     case 51:
673     case 52:
674     case 83:
675     case 84:
676     return(true);
677     }
678     return(false);
679     }
680    
681     bool OBAtom::IsNotCorH()
682     {
683     switch(GetAtomicNum())
684     {
685     case 1:
686     case 6:
687     return(false);
688     }
689     return(true);
690     }
691    
692     bool OBAtom::IsAromatic() const
693     {
694     if (((OBAtom*)this)->HasFlag(OB_AROMATIC_ATOM))
695     return(true);
696    
697     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
698    
699     if (!mol->HasAromaticPerceived())
700     {
701     aromtyper.AssignAromaticFlags(*mol);
702     if (((OBAtom*)this)->HasFlag(OB_AROMATIC_ATOM))
703     return(true);
704     }
705    
706     return(false);
707     }
708    
709     bool OBAtom::IsInRing() const
710     {
711     if (((OBAtom*)this)->HasFlag(OB_RING_ATOM))
712     return(true);
713    
714     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
715     if (!mol->HasRingAtomsAndBondsPerceived())
716     {
717     mol->FindRingAtomsAndBonds();
718     if (((OBAtom*)this)->HasFlag(OB_RING_ATOM))
719     return(true);
720     }
721    
722     return(false);
723     }
724    
725     bool OBAtom::IsChiral()
726     {
727     if (HasFlag(OB_CHIRAL_ATOM))
728     return(true);
729    
730     if (!((OBMol*)GetParent())->HasChiralityPerceived())
731     {
732     ((OBMol*)GetParent())->FindChiralCenters();
733     if (HasFlag(OB_CHIRAL_ATOM))
734     return(true);
735     }
736    
737     return(false);
738     }
739    
740     bool OBAtom::IsInRingSize(int size) const
741     {
742     vector<OBRing*> rlist;
743     vector<OBRing*>::iterator i;
744    
745     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
746     if (!mol->HasSSSRPerceived())
747     mol->FindSSSR();
748    
749     if (!((OBAtom*)this)->HasFlag(OB_RING_ATOM))
750     return(false);
751    
752     rlist = mol->GetSSSR();
753     for (i = rlist.begin();i != rlist.end();i++)
754     if ((*i)->IsInRing(GetIdx()) && (*i)->PathSize() == size)
755     return(true);
756    
757     return(false);
758     }
759    
760     unsigned int OBAtom::MemberOfRingCount() const
761     {
762     vector<OBRing*> rlist;
763     vector<OBRing*>::iterator i;
764     unsigned int count=0;
765    
766     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
767    
768     if (!mol->HasSSSRPerceived())
769     mol->FindSSSR();
770    
771     if (!((OBAtom*)this)->IsInRing())
772     return(0);
773    
774     rlist = mol->GetSSSR();
775    
776     for (i = rlist.begin();i != rlist.end();i++)
777     if ((*i)->IsInRing(GetIdx()))
778     count++;
779    
780     return((unsigned int)count);
781     }
782    
783     unsigned int OBAtom::MemberOfRingSize() const
784     {
785     vector<OBRing*> rlist;
786     vector<OBRing*>::iterator i;
787    
788     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
789    
790     if (!mol->HasSSSRPerceived())
791     mol->FindSSSR();
792    
793     if (!((OBAtom*)this)->IsInRing())
794     return(0);
795    
796     rlist = mol->GetSSSR();
797    
798     for (i = rlist.begin();i != rlist.end();i++)
799     if ((*i)->IsInRing(GetIdx()))
800     return((*i)->Size());
801    
802     return(0);
803     }
804    
805     double OBAtom::SmallestBondAngle()
806     {
807     OBAtom *b, *c;
808     vector3 v1, v2;
809     double degrees, minDegrees;
810     // vector<OBNodeBase*>::iterator i;
811     vector<OBEdgeBase*>::iterator j,k;
812    
813     minDegrees = 360.0;
814    
815     for (b = BeginNbrAtom(j); b; b = NextNbrAtom(j))
816     {
817     k = j;
818     for (c = NextNbrAtom(k); c; c = NextNbrAtom(k))
819     {
820     v1 = b->GetVector() - GetVector();
821     v2 = c->GetVector() - GetVector();
822     degrees = vectorAngle(v1, v2);
823     if (degrees < minDegrees)
824     minDegrees = degrees;
825     }
826     }
827     return minDegrees;
828     }
829    
830     double OBAtom::AverageBondAngle()
831     {
832     OBAtom *b, *c;
833     vector3 v1, v2;
834     double degrees, avgDegrees;
835     // vector<OBNodeBase*>::iterator i;
836     vector<OBEdgeBase*>::iterator j,k;
837     int n=0;
838    
839     avgDegrees = 0.0;
840    
841     for (b = BeginNbrAtom(j); b; b = NextNbrAtom(j))
842     {
843     k = j;
844     for (c = NextNbrAtom(k); c; c = NextNbrAtom(k))
845     {
846     v1 = b->GetVector() - GetVector();
847     v2 = c->GetVector() - GetVector();
848     degrees = vectorAngle(v1, v2);
849     avgDegrees += degrees;
850     n++;
851     }
852     }
853    
854     if (n >=1)
855     avgDegrees /= n;
856    
857     return avgDegrees;
858     }
859    
860     unsigned int OBAtom::CountFreeOxygens() const
861     {
862     unsigned int count = 0;
863     OBAtom *atom;
864     OBBond *bond;
865     vector<OBEdgeBase*>::iterator i;
866    
867     for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
868     {
869     atom = bond->GetNbrAtom((OBAtom*)this);
870     if (atom->IsOxygen() && atom->GetHvyValence() == 1)
871     count++;
872     }
873    
874     return(count);
875     }
876    
877     unsigned int OBAtom::BOSum() const
878     {
879     unsigned int bo;
880     unsigned int bosum=0;
881     OBBond *bond;
882     vector<OBEdgeBase*>::iterator i;
883    
884     for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
885     {
886     bo = bond->GetBO();
887     bosum += (bo < 4) ? 2*bo : 3;
888     }
889    
890     bosum /= 2;
891     return(bosum);
892     }
893    
894     unsigned int OBAtom::KBOSum() const
895     {
896     OBBond *bond;
897     unsigned int bosum;
898     vector<OBEdgeBase*>::iterator i;
899    
900     bosum = GetImplicitValence();
901    
902     for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
903     {
904     if (bond->IsKDouble())
905     bosum++;
906     else if (bond->IsKTriple())
907     bosum += 2;
908     }
909    
910     return(bosum);
911     }
912    
913     unsigned int OBAtom::ImplicitHydrogenCount() const
914     {
915     //handles H,C,N,S,O,X
916     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
917     if (mol && !mol->HasImplicitValencePerceived())
918     atomtyper.AssignImplicitValence(*((OBMol*)((OBAtom*)this)->GetParent()));
919    
920     int impval = _impval - GetHvyValence();
921     //Jan 05 Implicit valency now left alone; use spin multiplicity for implicit Hs
922     int mult = GetSpinMultiplicity();
923     if(mult==2) //radical
924     impval-=1;
925     else if(mult==1 || mult==3) //carbene
926     impval-=2;
927     return((impval>0)?impval:0);
928     }
929    
930     unsigned int OBAtom::ExplicitHydrogenCount() const
931     {
932     int numH=0;
933     OBAtom *atom;
934     vector<OBEdgeBase*>::iterator i;
935     for (atom = ((OBAtom*)this)->BeginNbrAtom(i);atom;atom = ((OBAtom*)this)->NextNbrAtom(i))
936     if (atom->IsHydrogen())
937     numH++;
938    
939     return(numH);
940     }
941    
942     bool OBAtom::DeleteBond(OBBond *bond)
943     {
944     vector<OBEdgeBase*>::iterator i;
945     for (i = _vbond.begin();i != _vbond.end();i++)
946     if ((OBBond*)bond == *i)
947     {
948     _vbond.erase(i);
949     return(true);
950     }
951     return(false);
952     }
953    
954     bool OBAtom::MatchesSMARTS(const char *pattern)
955     {
956     OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
957     vector<vector<int> > mlist;
958     vector<vector<int> >::iterator l;
959    
960     OBSmartsPattern test;
961     test.Init(pattern);
962     if (test.Match(*mol))
963     {
964     mlist = test.GetUMapList();
965     for (l = mlist.begin(); l != mlist.end(); l++)
966     if (GetIdx() == mol->GetAtom((*l)[0])->GetIdx())
967     return true;
968     }
969     return false;
970     }
971    
972     OBBond *OBAtom::BeginBond(vector<OBEdgeBase*>::iterator &i)
973     {
974     i = _vbond.begin();
975     return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
976     }
977    
978     OBBond *OBAtom::NextBond(vector<OBEdgeBase*>::iterator &i)
979     {
980     i++;
981     return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
982     }
983    
984     OBAtom *OBAtom::BeginNbrAtom(vector<OBEdgeBase*>::iterator &i)
985     {
986     i = _vbond.begin();
987     return((i != _vbond.end()) ? ((OBBond*) *i)->GetNbrAtom(this):NULL);
988     }
989    
990     OBAtom *OBAtom::NextNbrAtom(vector<OBEdgeBase*>::iterator &i)
991     {
992     i++;
993     return((i != _vbond.end()) ? ((OBBond*) *i)->GetNbrAtom(this):NULL);
994     }
995    
996     double OBAtom::GetDistance(OBAtom *b)
997     {
998     return(( this->GetVector() - b->GetVector() ).length());
999     }
1000    
1001     double OBAtom::GetDistance(int b)
1002     {
1003     OBMol *mol = (OBMol*)GetParent();
1004     return(( this->GetVector() - mol->GetAtom(b)->GetVector() ).length());
1005     }
1006    
1007     double OBAtom::GetAngle(OBAtom *b, OBAtom *c)
1008     {
1009     vector3 v1,v2;
1010    
1011     v1 = this->GetVector() - b->GetVector();
1012     v2 = c->GetVector() - b->GetVector();
1013    
1014     return(vectorAngle(v1, v2));
1015     }
1016    
1017     double OBAtom::GetAngle(int b, int c)
1018     {
1019     OBMol *mol = (OBMol*)GetParent();
1020     vector3 v1,v2;
1021    
1022     v1 = this->GetVector() - mol->GetAtom(b)->GetVector();
1023     v2 = mol->GetAtom(c)->GetVector() - mol->GetAtom(b)->GetVector();
1024    
1025     return(vectorAngle(v1, v2));
1026     }
1027    
1028     bool OBAtom::GetNewBondVector(vector3 &v,double length)
1029     {
1030     // ***experimental code***
1031    
1032     OBAtom *atom;
1033     vector<OBEdgeBase*>::iterator i,j;
1034     v = VZero;
1035    
1036     if (GetValence() == 0)
1037     {
1038     v = VX;
1039     v *= length;
1040     v += GetVector();
1041     return(true);
1042     }
1043    
1044     if (GetValence() == 1)
1045     {
1046     vector3 vtmp,v1,v2;
1047     atom = BeginNbrAtom(i);
1048     if (atom)
1049     vtmp = GetVector() - atom->GetVector();
1050    
1051     if (GetHyb() == 2 || (IsOxygen() && HasAlphaBetaUnsat()))
1052     {
1053     bool quit = false;
1054     OBAtom *a1,*a2;
1055     v2 = VZero;
1056     for (a1 = BeginNbrAtom(i);a1 && !quit;a1 = NextNbrAtom(i))
1057     for (a2 = a1->BeginNbrAtom(j);a2 && !quit;a2 = a1->NextNbrAtom(j))
1058     if (a1 && a2 && a2 != this)
1059     {
1060     v2 = a1->GetVector() - a2->GetVector();
1061     quit = true;
1062     }
1063    
1064     if (v2 == VZero)
1065     {
1066     v1 = cross(vtmp,VX);
1067     v2 = cross(vtmp,VY);
1068     if (v1.length() < v2.length())
1069     v1 = v2;
1070     }
1071     else
1072     v1 = cross(vtmp,v2);
1073    
1074     matrix3x3 m;
1075     m.RotAboutAxisByAngle(v1,60.0);
1076     v = m*vtmp;
1077     v.normalize();
1078     }
1079     else if (GetHyb() == 3)
1080     {
1081     v1 = cross(vtmp,VX);
1082     v2 = cross(vtmp,VY);
1083     if (v1.length() < v2.length())
1084     v1 = v2;
1085     matrix3x3 m;
1086     m.RotAboutAxisByAngle(v1,70.5);
1087     v = m*vtmp;
1088     v.normalize();
1089     }
1090     if (GetHyb() == 1)
1091     v = vtmp;
1092    
1093     v *= length;
1094     v += GetVector();
1095     return(true);
1096     }
1097    
1098     if (GetValence() == 2)
1099     {
1100     vector3 v1,v2,vtmp,vsum,vnorm;
1101     atom = BeginNbrAtom(i);
1102     if (!atom)
1103     return(false);
1104     v1 = GetVector() - atom->GetVector();
1105     atom = NextNbrAtom(i);
1106     if (!atom)
1107     return(false);
1108     v2 = GetVector() - atom->GetVector();
1109     v1.normalize();
1110     v2.normalize();
1111     vsum = v1+v2;
1112     vsum.normalize();
1113    
1114     if (GetHyb() == 2)
1115     v = vsum;
1116     else if (GetHyb() == 3)
1117     {
1118     vnorm = cross(v2,v1);
1119     vnorm.normalize();
1120    
1121     #ifndef ONE_OVER_SQRT3
1122     #define ONE_OVER_SQRT3 0.57735026918962576451
1123     #endif //SQRT_TWO_THIRDS
1124     #ifndef SQRT_TWO_THIRDS
1125     #define SQRT_TWO_THIRDS 0.81649658092772603272
1126     #endif //ONE_OVER_SQRT3
1127    
1128     vsum *= ONE_OVER_SQRT3;
1129     vnorm *= SQRT_TWO_THIRDS;
1130    
1131     v = vsum + vnorm;
1132     }
1133    
1134     v *= length;
1135    
1136     v += GetVector();
1137     return(true);
1138     }
1139    
1140     if (GetValence() == 3)
1141     {
1142     vector3 vtmp,vsum;
1143     OBAtom *atom;
1144     vector<OBEdgeBase*>::iterator i;
1145     for (atom = BeginNbrAtom(i);atom;atom = NextNbrAtom(i))
1146     {
1147     vtmp = GetVector() - atom->GetVector();
1148     vtmp.normalize();
1149     vtmp /= 3.0;
1150     vsum += vtmp;
1151     }
1152     vsum.normalize();
1153     v = vsum;
1154     v *= length;
1155     v += GetVector();
1156     return(true);
1157     }
1158    
1159     return(true);
1160     }
1161    
1162     bool OBAtom::HtoMethyl()
1163     {
1164     if (!IsHydrogen())
1165     return(false);
1166    
1167     obErrorLog.ThrowError(__FUNCTION__,
1168     "Ran OpenBabel::HtoMethyl", obAuditMsg);
1169    
1170     OBMol *mol = (OBMol*)GetParent();
1171    
1172     mol->BeginModify();
1173    
1174     SetAtomicNum(6);
1175     SetType("C3");
1176     SetHyb(3);
1177    
1178     OBAtom *atom;
1179     OBBond *bond;
1180     vector<OBEdgeBase*>::iterator i;
1181     atom = BeginNbrAtom(i);
1182     bond = (OBBond *)*i;
1183     if (!atom)
1184     {
1185     mol->EndModify();
1186     return(false);
1187     }
1188    
1189     double br1,br2;
1190     br1 = etab.CorrectedBondRad(6,3);
1191     br2 = etab.CorrectedBondRad(atom->GetAtomicNum(),atom->GetHyb());
1192     bond->SetLength(atom,br1+br2);
1193    
1194     OBAtom *hatom;
1195     br2 = etab.CorrectedBondRad(1,0);
1196     vector3 v;
1197    
1198     for (int j = 0;j < 3;j++)
1199     {
1200     hatom = mol->NewAtom();
1201     hatom->SetAtomicNum(1);
1202     hatom->SetType("H");
1203    
1204     GetNewBondVector(v,br1+br2);
1205     hatom->SetVector(v);
1206     mol->AddBond(GetIdx(),mol->NumAtoms(),1);
1207     }
1208    
1209     mol->EndModify();
1210     return(true);
1211     }
1212    
1213     static void ApplyRotMatToBond(OBMol &mol,matrix3x3 &m,OBAtom *a1,OBAtom *a2)
1214     {
1215     vector<int> children;
1216     mol.FindChildren(children,a1->GetIdx(),a2->GetIdx());
1217     children.push_back(a2->GetIdx());
1218    
1219     vector3 v;
1220     vector<int>::iterator i;
1221     for (i = children.begin();i != children.end();i++)
1222     {
1223     v = mol.GetAtom(*i)->GetVector();
1224     v -= a1->GetVector();
1225     v *= m;
1226     v += a1->GetVector();
1227     mol.GetAtom(*i)->SetVector(v);
1228     }
1229    
1230     }
1231    
1232     bool OBAtom::SetHybAndGeom(int hyb)
1233     {
1234     obErrorLog.ThrowError(__FUNCTION__,
1235     "Ran OpenBabel::SetHybridizationAndGeometry",
1236     obAuditMsg);
1237    
1238     //if (hyb == GetHyb()) return(true);
1239     if (GetAtomicNum() == 1)
1240     return(false);
1241     if (hyb == 0 && GetHvyValence() > 1)
1242     return(false);
1243     if (hyb == 1 && GetHvyValence() > 2)
1244     return(false);
1245     if (hyb == 2 && GetHvyValence() > 3)
1246     return(false);
1247     if (hyb == 3 && GetHvyValence() > 4)
1248     return(false);
1249    
1250     OBMol *mol = (OBMol*)GetParent();
1251    
1252     OBAtom *nbr;
1253     vector<OBAtom*> delatm;
1254     vector<OBEdgeBase*>::iterator i;
1255    
1256     for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1257     if (nbr->IsHydrogen())
1258     delatm.push_back(nbr);
1259    
1260     //delete attached hydrogens
1261     mol->IncrementMod();
1262     vector<OBAtom*>::iterator j;
1263     for (j = delatm.begin();j != delatm.end();j++)
1264     mol->DeleteAtom(*j);
1265     mol->DecrementMod();
1266    
1267     double targetAngle;
1268     if (hyb == 3)
1269     targetAngle = 109.5;
1270     else if (hyb == 2)
1271     targetAngle = 120.0;
1272     else if (hyb == 1)
1273     targetAngle = 180.0;
1274     else
1275     targetAngle = 0.0;
1276    
1277     if (IsInRing())
1278     targetAngle = 180.0 - (360.0 / MemberOfRingSize());
1279    
1280     //adjust attached acyclic bond lengths
1281     double br1,br2, length;
1282     br1 = etab.CorrectedBondRad(GetAtomicNum(),hyb);
1283     for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1284     if (!(*i)->IsInRing())
1285     {
1286     br2 = etab.CorrectedBondRad(nbr->GetAtomicNum(),nbr->GetHyb());
1287     length = br1 + br2;
1288     if ((*i)->IsAromatic())
1289     length *= 0.93;
1290     else if ((*i)->GetBO() == 2)
1291     length *= 0.91;
1292     else if ((*i)->GetBO() == 3)
1293     length *= 0.87;
1294     ((OBBond*) *i)->SetLength(this, length);
1295     }
1296    
1297     if (GetValence() > 1)
1298     {
1299     double angle;
1300     matrix3x3 m;
1301     vector3 v1,v2,v3,v4,n,s;
1302     OBAtom *r1,*r2,*r3,*a1,*a2,*a3,*a4;
1303     r1 = r2 = r3 = a1 = a2 = a3 = a4 = NULL;
1304    
1305     //find ring atoms first
1306     for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1307     if ((*i)->IsInRing())
1308     if (!r1)
1309     r1 = nbr;
1310     else if (!r2)
1311     r2 = nbr;
1312     else if (!r3)
1313     r3 = nbr;
1314    
1315     //find non-ring atoms
1316     for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1317     if (!(*i)->IsInRing())
1318     if (!a1)
1319     a1 = nbr;
1320     else if (!a2)
1321     a2 = nbr;
1322     else if (!a3)
1323     a3 = nbr;
1324     else if (!a4)
1325     a4 = nbr;
1326    
1327     //adjust geometries of heavy atoms according to hybridization
1328     if (hyb == 1)
1329     {
1330     if (a2)
1331     {
1332     v1 = a1->GetVector()-GetVector();
1333     v1.normalize();
1334     v2 = a2->GetVector()-GetVector();
1335     v2.normalize();
1336     n = cross(v1,v2);
1337     angle = vectorAngle(v1,v2)-targetAngle;
1338     m.RotAboutAxisByAngle(n,-angle);
1339     ApplyRotMatToBond(*mol,m,this,a1);
1340     }
1341     }
1342     else if (hyb == 2)
1343     {
1344     if (r1 && r2 && a1)
1345     {
1346     v1 = r1->GetVector()-GetVector();
1347     v1.normalize();
1348     v2 = r2->GetVector()-GetVector();
1349     v2.normalize();
1350     v3 = a1->GetVector()-GetVector();
1351     s = v1+v2;
1352     s.normalize();
1353     s *= -1.0;
1354     n = cross(s,v3);
1355     angle = vectorAngle(s,v3);
1356     m.RotAboutAxisByAngle(n,angle);
1357     ApplyRotMatToBond(*mol,m,this,a1);
1358     }
1359     else
1360     {
1361     if (a2)
1362     {
1363     v1 = a1->GetVector()-GetVector();
1364     v1.normalize();
1365     v2 = a2->GetVector()-GetVector();
1366     v2.normalize();
1367     n = cross(v1,v2);
1368     angle = vectorAngle(v1,v2)-targetAngle;
1369     m.RotAboutAxisByAngle(n,-angle);
1370     ApplyRotMatToBond(*mol,m,this,a1);
1371     }
1372     if (a3)
1373     {
1374     v1 = a1->GetVector()-GetVector();
1375     v1.normalize();
1376     v2 = a2->GetVector()-GetVector();
1377     v2.normalize();
1378     v3 = a3->GetVector()-GetVector();
1379     s = v1+v2;
1380     s.normalize();
1381     s *= -1.0;
1382     n = cross(s,v3);
1383     angle = vectorAngle(s,v3);
1384     m.RotAboutAxisByAngle(n,angle);
1385     ApplyRotMatToBond(*mol,m,this,a3);
1386     }
1387     }
1388     }
1389     else if (hyb == 3)
1390     {
1391     if (r1 && r2 && r3 && a1)
1392     {
1393     v1 = r1->GetVector()-GetVector();
1394     v1.normalize();
1395     v2 = r2->GetVector()-GetVector();
1396     v2.normalize();
1397     v3 = r3->GetVector()-GetVector();
1398     v3.normalize();
1399     v4 = a1->GetVector()-GetVector();
1400     s = v1 + v2 + v3;
1401     s *= -1.0;
1402     s.normalize();
1403     n = cross(s,v4);
1404     angle = vectorAngle(s,v4);
1405     m.RotAboutAxisByAngle(n,angle);
1406     ApplyRotMatToBond(*mol,m,this,a1);
1407     }
1408     else if (r1 && r2 && !r3 && a1)
1409     {
1410     v1 = r1->GetVector()-GetVector();
1411     v1.normalize();
1412     v2 = r2->GetVector()-GetVector();
1413     v2.normalize();
1414     v3 = a1->GetVector()-GetVector();
1415     s = v1+v2;
1416     s *= -1.0;
1417     s.normalize();
1418     n = cross(v1,v2);
1419     n.normalize();
1420     s *= ONE_OVER_SQRT3; //1/sqrt(3)
1421     n *= SQRT_TWO_THIRDS; //sqrt(2/3)
1422     s += n;
1423     s.normalize();
1424     n = cross(s,v3);
1425     angle = vectorAngle(s,v3);
1426     m.RotAboutAxisByAngle(n,angle);
1427     ApplyRotMatToBond(*mol,m,this,a1);
1428    
1429     if (a2)
1430     {
1431     v1 = r1->GetVector()-GetVector();
1432     v1.normalize();
1433     v2 = r2->GetVector()-GetVector();
1434     v2.normalize();
1435     v3 = a1->GetVector()-GetVector();
1436     v3.normalize();
1437     v4 = a2->GetVector()-GetVector();
1438     s = v1 + v2 + v3;
1439     s *= -1.0;
1440     s.normalize();
1441     n = cross(s,v4);
1442     angle = vectorAngle(s,v4);
1443     m.RotAboutAxisByAngle(n,angle);
1444     ApplyRotMatToBond(*mol,m,this,a2);
1445     }
1446     }
1447     else
1448     {
1449     if (a2)
1450     {
1451     v1 = a1->GetVector()-GetVector();
1452     v1.normalize();
1453     v2 = a2->GetVector()-GetVector();
1454     v2.normalize();
1455     n = cross(v1,v2);
1456     angle = vectorAngle(v1,v2)-targetAngle;
1457     m.RotAboutAxisByAngle(n,-angle);
1458     ApplyRotMatToBond(*mol,m,this,a1);
1459     }
1460     if (a3)
1461     {
1462     v1 = a1->GetVector()-GetVector();
1463     v1.normalize();
1464     v2 = a2->GetVector()-GetVector();
1465     v2.normalize();
1466     v3 = a3->GetVector()-GetVector();
1467     s = v1+v2;
1468     s *= -1.0;
1469     s.normalize();
1470     n = cross(v1,v2);
1471     n.normalize();
1472     s *= ONE_OVER_SQRT3; //1/sqrt(3)
1473     n *= SQRT_TWO_THIRDS; //sqrt(2/3)
1474     s += n;
1475     s.normalize();
1476     n = cross(s,v3);
1477     angle = vectorAngle(s,v3);
1478     m.RotAboutAxisByAngle(n,angle);
1479     ApplyRotMatToBond(*mol,m,this,a3);
1480     }
1481     }
1482     }
1483     }
1484    
1485     //add hydrogens back to atom
1486     int impval=1;
1487     switch (GetAtomicNum())
1488     {
1489     case 6:
1490     if (hyb == 3)
1491     impval = 4;
1492     if (hyb == 2)
1493     impval = 3;
1494     if (hyb == 1)
1495     impval = 2;
1496     break;
1497     case 7:
1498     if (hyb == 3)
1499     impval = 3;
1500     if (hyb == 2)
1501     impval = 2;
1502     if (hyb == 1)
1503     impval = 1;
1504     break;
1505     case 8:
1506     if (hyb == 3)
1507     impval = 2;
1508     if (hyb == 2)
1509     impval = 2;
1510     if (hyb == 1)
1511     impval = 2;
1512     case 16:
1513     if (hyb == 3)
1514     impval = 2;
1515     if (hyb == 2)
1516     impval = 2;
1517     if (hyb == 1)
1518     impval = 0;
1519     break;
1520     case 15:
1521     if (hyb == 3)
1522     impval = 4;
1523     if (hyb == 2)
1524     impval = 3;
1525     if (hyb == 1)
1526     impval = 2;
1527     break;
1528     default:
1529     impval = 1;
1530     }
1531    
1532     int hcount = impval-GetHvyValence();
1533     if (hcount)
1534     {
1535     int k;
1536     vector3 v;
1537     OBAtom *atom;
1538     double brsum = etab.CorrectedBondRad(1,0)+
1539     etab.CorrectedBondRad(GetAtomicNum(),GetHyb());
1540     SetHyb(hyb);
1541    
1542     mol->BeginModify();
1543     for (k = 0;k < hcount;k++)
1544     {
1545     GetNewBondVector(v,brsum);
1546     atom = mol->NewAtom();
1547     atom->SetAtomicNum(1);
1548     atom->SetType("H");
1549     atom->SetVector(v);
1550     mol->AddBond(atom->GetIdx(),GetIdx(),1);
1551     }
1552     mol->EndModify();
1553     }
1554    
1555    
1556     return(true);
1557     }
1558    
1559     OBBond *OBAtom::GetBond(OBAtom *nbr)
1560     {
1561     OBBond *bond;
1562     vector<OBEdgeBase *>::iterator i;
1563     for (bond = BeginBond(i) ; bond ; bond = NextBond(i))
1564     if (bond->GetNbrAtom(this) == nbr)
1565     return bond;
1566     return NULL;
1567     }
1568    
1569     // OBGenericData methods
1570     bool OBAtom::HasData(string &s)
1571     //returns true if the generic attribute/value pair exists
1572     {
1573     if (_vdata.empty())
1574     return(false);
1575    
1576     vector<OBGenericData*>::iterator i;
1577    
1578     for (i = _vdata.begin();i != _vdata.end();i++)
1579     if ((*i)->GetAttribute() == s)
1580     return(true);
1581    
1582     return(false);
1583     }
1584    
1585     bool OBAtom::HasData(const char *s)
1586     //returns true if the generic attribute/value pair exists
1587     {
1588     if (_vdata.empty())
1589     return(false);
1590    
1591     vector<OBGenericData*>::iterator i;
1592    
1593     for (i = _vdata.begin();i != _vdata.end();i++)
1594     if ((*i)->GetAttribute() == s)
1595     return(true);
1596    
1597     return(false);
1598     }
1599    
1600     bool OBAtom::HasData(unsigned int dt)
1601     //returns true if the generic attribute/value pair exists
1602     {
1603     if (_vdata.empty())
1604     return(false);
1605    
1606     vector<OBGenericData*>::iterator i;
1607    
1608     for (i = _vdata.begin();i != _vdata.end();i++)
1609     if ((*i)->GetDataType() == dt)
1610     return(true);
1611    
1612     return(false);
1613     }
1614    
1615     OBGenericData *OBAtom::GetData(string &s)
1616     //returns the value given an attribute
1617     {
1618     vector<OBGenericData*>::iterator i;
1619    
1620     for (i = _vdata.begin();i != _vdata.end();i++)
1621     if ((*i)->GetAttribute() == s)
1622     return(*i);
1623    
1624     return(NULL);
1625     }
1626    
1627     OBGenericData *OBAtom::GetData(const char *s)
1628     //returns the value given an attribute
1629     {
1630     vector<OBGenericData*>::iterator i;
1631    
1632     for (i = _vdata.begin();i != _vdata.end();i++)
1633     if ((*i)->GetAttribute() == s)
1634     return(*i);
1635    
1636     return(NULL);
1637     }
1638    
1639     OBGenericData *OBAtom::GetData(unsigned int dt)
1640     {
1641     vector<OBGenericData*>::iterator i;
1642     for (i = _vdata.begin();i != _vdata.end();i++)
1643     if ((*i)->GetDataType() == dt)
1644     return(*i);
1645     return(NULL);
1646     }
1647    
1648     void OBAtom::DeleteData(unsigned int dt)
1649     {
1650     vector<OBGenericData*> vdata;
1651     vector<OBGenericData*>::iterator i;
1652     for (i = _vdata.begin();i != _vdata.end();i++)
1653     if ((*i)->GetDataType() == dt)
1654     delete *i;
1655     else
1656     vdata.push_back(*i);
1657     _vdata = vdata;
1658     }
1659    
1660     void OBAtom::DeleteData(vector<OBGenericData*> &vg)
1661     {
1662     vector<OBGenericData*> vdata;
1663     vector<OBGenericData*>::iterator i,j;
1664    
1665     bool del;
1666     for (i = _vdata.begin();i != _vdata.end();i++)
1667     {
1668     del = false;
1669     for (j = vg.begin();j != vg.end();j++)
1670     if (*i == *j)
1671     {
1672     del = true;
1673     break;
1674     }
1675     if (del)
1676     delete *i;
1677     else
1678     vdata.push_back(*i);
1679     }
1680     _vdata = vdata;
1681     }
1682    
1683     void OBAtom::DeleteData(OBGenericData *gd)
1684     {
1685     vector<OBGenericData*>::iterator i;
1686     for (i = _vdata.begin();i != _vdata.end();i++)
1687     if (*i == gd)
1688     {
1689     delete *i;
1690     _vdata.erase(i);
1691     }
1692    
1693     }
1694    
1695     bool OBAtom::IsHbondAcceptor()
1696     {
1697     return _ele == 7 || _ele == 8 || _ele == 9 ;
1698     }
1699    
1700     bool OBAtom::IsHbondDonor()
1701     {
1702     return MatchesSMARTS("[$([#8,#7H,#9;!H0])]");
1703     }
1704    
1705     bool OBAtom::IsHbondDonorH()
1706     {
1707     if (!IsHydrogen()) return(false);
1708    
1709     OBAtom *atom;
1710     OBBond *bond;
1711     vector<OBEdgeBase*>::iterator i;
1712     for (bond = BeginBond(i);bond;bond = NextBond(i))
1713     {
1714     atom = bond->GetNbrAtom(this);
1715     if (atom->GetAtomicNum() == 7) return(true);
1716     if (atom->GetAtomicNum() == 8) return(true);
1717     if (atom->GetAtomicNum() == 9) return(true);
1718     }
1719    
1720     return(false);
1721     }
1722    
1723     } // end namespace OpenBabel
1724    
1725     //! \file atom.cpp
1726     //! \brief Handle OBAtom class