/src/openbabel/src/bond.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | bond.cpp - Handle OBBond class |
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 <openbabel/elements.h> |
22 | | #include <openbabel/oberror.h> |
23 | | #include <openbabel/obutil.h> |
24 | | #include <openbabel/ring.h> |
25 | | #include <openbabel/bond.h> |
26 | | #include <openbabel/mol.h> |
27 | | #include <openbabel/generic.h> |
28 | | #include <climits> |
29 | | |
30 | | using namespace std; |
31 | | |
32 | | namespace OpenBabel |
33 | | { |
34 | | |
35 | | class OBBondPrivate |
36 | | { |
37 | | public: |
38 | 0 | OBBondPrivate() {} |
39 | | }; |
40 | | |
41 | | extern THREAD_LOCAL OBAromaticTyper aromtyper; |
42 | | extern OBMessageHandler obErrorLog; |
43 | | |
44 | | /** \class OBBond bond.h <openbabel/bond.h> |
45 | | \brief Bond class |
46 | | |
47 | | The OBBond class is straightforward in its data access and |
48 | | modification methods. OBBonds store pointers to the atoms on each end |
49 | | of the bond. In storing pointers to atoms instead of integer indices, |
50 | | the necessity of having to reorder bonds when atoms are shuffled, |
51 | | added, or delete is obviated. |
52 | | |
53 | | While methods indicate "begin" and "end" atoms in the bond, all methods |
54 | | are designed to be independent of atom ordering, with the exception of |
55 | | stereochemically aware properties such as IsUp(), IsDown(), IsWedge, or |
56 | | IsHash(). |
57 | | */ |
58 | | |
59 | | // ******************************* |
60 | | // *** OBBond member functions *** |
61 | | // ******************************* |
62 | | |
63 | | OBBond::OBBond() /*: d(new OBBondPrivate)*/ |
64 | 84.7M | { |
65 | 84.7M | _idx=0; |
66 | 84.7M | _order=0; |
67 | 84.7M | _flags=0; |
68 | 84.7M | _bgn=nullptr; |
69 | 84.7M | _end=nullptr; |
70 | 84.7M | _vdata.clear(); |
71 | 84.7M | _parent=nullptr; |
72 | 84.7M | } |
73 | | |
74 | | OBBond::~OBBond() |
75 | 84.7M | { |
76 | | // OBGenericData handled in OBBase parent class. |
77 | 84.7M | } |
78 | | |
79 | | /** Mark the main information for a bond |
80 | | \param idx The unique bond index for this bond (inside an OBMol) |
81 | | \param begin The 'beginning' atom for the bond |
82 | | \param end The 'end' atom for the bond |
83 | | \param order The bond order (i.e., 1 = single, 2 = double... 5 = aromatic) |
84 | | \param flags Any initial property flags |
85 | | **/ |
86 | | void OBBond::Set(int idx,OBAtom *begin,OBAtom *end,int order,int flags) |
87 | 84.7M | { |
88 | 84.7M | SetIdx(idx); |
89 | 84.7M | SetBegin(begin); |
90 | 84.7M | SetEnd(end); |
91 | 84.7M | SetBondOrder(order); |
92 | 84.7M | SetFlag(flags); |
93 | 84.7M | } |
94 | | |
95 | | void OBBond::SetBondOrder(int order) |
96 | 92.1M | { |
97 | 92.1M | _order = (char)order; |
98 | 92.1M | } |
99 | | |
100 | | // TODO: Figure out how to consider periodicity, etc. |
101 | | void OBBond::SetLength(OBAtom *fixed, double length) |
102 | 0 | { |
103 | 0 | unsigned int i; |
104 | 0 | OBMol *mol = (OBMol*)fixed->GetParent(); |
105 | 0 | vector3 v1,v2,v3,v4,v5; |
106 | 0 | vector<int> children; |
107 | |
|
108 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
109 | 0 | "Ran OpenBabel::SetBondLength", obAuditMsg); |
110 | |
|
111 | 0 | int a = fixed->GetIdx(); |
112 | 0 | int b = GetNbrAtom(fixed)->GetIdx(); |
113 | |
|
114 | 0 | if (a == b) |
115 | 0 | return; // this would be a problem... |
116 | | |
117 | 0 | mol->FindChildren(children,a,b); |
118 | 0 | children.push_back(b); |
119 | |
|
120 | 0 | v1 = GetNbrAtom(fixed)->GetVector(); |
121 | 0 | v2 = fixed->GetVector(); |
122 | 0 | v3 = v1 - v2; |
123 | |
|
124 | 0 | if (fabs(v3.length_2()) < 2e-6) { // too small to normalize, move the atoms apart |
125 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
126 | 0 | "Atoms are both at the same location, moving out of the way.", obWarning); |
127 | 0 | v3.randomUnitVector(); |
128 | 0 | } else { |
129 | 0 | v3.normalize(); |
130 | 0 | } |
131 | |
|
132 | 0 | v3 *= length; |
133 | 0 | v3 += v2; |
134 | 0 | v4 = v3 - v1; |
135 | |
|
136 | 0 | for ( i = 0 ; i < children.size() ; i++ ) |
137 | 0 | { |
138 | 0 | v1 = mol->GetAtom(children[i])->GetVector(); |
139 | 0 | v1 += v4; |
140 | 0 | mol->GetAtom(children[i])->SetVector(v1); |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | void OBBond::SetLength(double length) |
145 | 0 | { |
146 | 0 | OBAtom *atom1 = GetBeginAtom(); |
147 | 0 | OBAtom *atom2 = GetEndAtom(); |
148 | | |
149 | | //split the length difference in half, and modify the bond twice |
150 | 0 | double firstLength = length + ((GetLength() - length) / 2); |
151 | |
|
152 | 0 | SetLength(atom1, firstLength); |
153 | 0 | SetLength(atom2, length); |
154 | 0 | } |
155 | | |
156 | | bool OBBond::IsRotor(bool includeRingBonds) |
157 | 716k | { |
158 | | // This could be one hellish conditional, but let's break it down |
159 | | // .. the bond is a single bond |
160 | 716k | if (_order != 1) |
161 | 82.2k | return false; |
162 | | |
163 | | // not in a ring, or in a large ring |
164 | | // and if it's a ring, not sp2 |
165 | 634k | OBRing *ring = FindSmallestRing(); |
166 | 634k | if (ring != nullptr) { |
167 | 185k | if(!includeRingBonds) |
168 | 185k | return false; |
169 | 0 | if (ring->Size() <= 3) |
170 | 0 | return false; |
171 | 0 | if (_bgn->GetHyb() == 2 || _end->GetHyb() == 2) |
172 | 0 | return false; |
173 | 0 | } |
174 | | |
175 | | // atoms are not sp hybrids |
176 | 448k | if (_bgn->GetHyb() == 1 || _end->GetHyb() == 1) |
177 | 340k | return false; |
178 | | |
179 | | // not just an -OH or -NH2, etc. |
180 | | // maybe we want to add this as an option |
181 | | // rotatable = rotatable && ((_bgn->IsHeteroatom() || _bgn->GetHvyDegree() > 1) |
182 | | // && (_end->IsHeteroatom() || _end->GetHvyDegree() > 1) ); |
183 | 107k | return (_bgn->GetHvyDegree() > 1 && _end->GetHvyDegree() > 1); |
184 | 448k | } |
185 | | |
186 | | bool OBBond::IsPeriodic() const |
187 | 118M | { |
188 | 118M | OBMol *mol = (OBMol*)((OBBond*)this)->GetParent(); |
189 | 118M | return mol->IsPeriodic(); |
190 | 118M | } |
191 | | |
192 | | bool OBBond::IsAmide() |
193 | 0 | { |
194 | 0 | OBAtom *c,*n; |
195 | 0 | c = n = nullptr; |
196 | | |
197 | | // Look for C-N bond |
198 | 0 | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
199 | 0 | { |
200 | 0 | c = (OBAtom*)_bgn; |
201 | 0 | n = (OBAtom*)_end; |
202 | 0 | } |
203 | 0 | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
204 | 0 | { |
205 | 0 | c = (OBAtom*)_end; |
206 | 0 | n = (OBAtom*)_bgn; |
207 | 0 | } |
208 | 0 | if (!c || !n) return(false); |
209 | 0 | if (GetBondOrder() != 1) return(false); |
210 | 0 | if (n->GetTotalDegree() != 3) return false; // must be a degree 3 nitrogen |
211 | | |
212 | | // Make sure C is attached to =O |
213 | 0 | OBBond *bond; |
214 | 0 | vector<OBBond*>::iterator i; |
215 | 0 | for (bond = c->BeginBond(i); bond; bond = c->NextBond(i)) |
216 | 0 | { |
217 | 0 | if (bond->IsCarbonyl()) return(true); |
218 | 0 | } |
219 | | |
220 | | // Return |
221 | 0 | return(false); |
222 | 0 | } |
223 | | |
224 | | bool OBBond::IsPrimaryAmide() |
225 | 0 | { |
226 | 0 | OBAtom *c,*n; |
227 | 0 | c = n = nullptr; |
228 | | |
229 | | // Look for C-N bond |
230 | 0 | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
231 | 0 | { |
232 | 0 | c = (OBAtom*)_bgn; |
233 | 0 | n = (OBAtom*)_end; |
234 | 0 | } |
235 | 0 | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
236 | 0 | { |
237 | 0 | c = (OBAtom*)_end; |
238 | 0 | n = (OBAtom*)_bgn; |
239 | 0 | } |
240 | 0 | if (!c || !n) return(false); |
241 | 0 | if (GetBondOrder() != 1) return(false); |
242 | 0 | if (n->GetTotalDegree() != 3) return false; // must be a degree 3 nitrogen |
243 | | |
244 | | // Make sure that N is connected to one non-H |
245 | 0 | if (n->GetHvyDegree() != 1) return(false); |
246 | | |
247 | | // Make sure C is attached to =O |
248 | 0 | OBBond *bond; |
249 | 0 | vector<OBBond*>::iterator i; |
250 | 0 | for (bond = c->BeginBond(i); bond; bond = c->NextBond(i)) |
251 | 0 | { |
252 | 0 | if (bond->IsCarbonyl()) return(true); |
253 | 0 | } |
254 | | |
255 | 0 | return(false); |
256 | 0 | } |
257 | | |
258 | | bool OBBond::IsSecondaryAmide() |
259 | 0 | { |
260 | 0 | OBAtom *c,*n; |
261 | 0 | c = n = nullptr; |
262 | | |
263 | | // Look for C-N bond |
264 | 0 | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
265 | 0 | { |
266 | 0 | c = (OBAtom*)_bgn; |
267 | 0 | n = (OBAtom*)_end; |
268 | 0 | } |
269 | 0 | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
270 | 0 | { |
271 | 0 | c = (OBAtom*)_end; |
272 | 0 | n = (OBAtom*)_bgn; |
273 | 0 | } |
274 | 0 | if (!c || !n) return(false); |
275 | 0 | if (GetBondOrder() != 1) return(false); |
276 | 0 | if (n->GetTotalDegree() != 3) return false; // must be a degree 3 nitrogen |
277 | | |
278 | | // Make sure that N is connected to two non-H atoms |
279 | 0 | if (n->GetHvyDegree() != 2) return(false); |
280 | | |
281 | | // Make sure C is attached to =O |
282 | 0 | OBBond *bond; |
283 | 0 | vector<OBBond*>::iterator i; |
284 | 0 | for (bond = c->BeginBond(i); bond; bond = c->NextBond(i)) |
285 | 0 | { |
286 | 0 | if (bond->IsCarbonyl()) return(true); |
287 | 0 | } |
288 | | |
289 | 0 | return(false); |
290 | 0 | } |
291 | | |
292 | | bool OBBond::IsTertiaryAmide() |
293 | 0 | { |
294 | 0 | OBAtom *c,*n; |
295 | 0 | c = n = nullptr; |
296 | | |
297 | | // Look for C-N bond |
298 | 0 | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
299 | 0 | { |
300 | 0 | c = (OBAtom*)_bgn; |
301 | 0 | n = (OBAtom*)_end; |
302 | 0 | } |
303 | 0 | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
304 | 0 | { |
305 | 0 | c = (OBAtom*)_end; |
306 | 0 | n = (OBAtom*)_bgn; |
307 | 0 | } |
308 | 0 | if (!c || !n) return(false); |
309 | 0 | if (GetBondOrder() != 1) return(false); |
310 | 0 | if (n->GetTotalDegree() != 3) return false; // must be a degree 3 nitrogen |
311 | | |
312 | | // Make sure that N is connected to three non-H atoms |
313 | 0 | if (n->GetHvyDegree() != 3) return(false); |
314 | | |
315 | | // Make sure C is attached to =O |
316 | 0 | OBBond *bond; |
317 | 0 | vector<OBBond*>::iterator i; |
318 | 0 | for (bond = c->BeginBond(i); bond; bond = c->NextBond(i)) |
319 | 0 | { |
320 | 0 | if (bond->IsCarbonyl()) return(true); |
321 | 0 | } |
322 | | |
323 | 0 | return(false); |
324 | 0 | } |
325 | | |
326 | | /* |
327 | | bool OBBond::IsAmide() |
328 | | { |
329 | | OBAtom *a1,*a2; |
330 | | a1 = a2 = NULL; |
331 | | |
332 | | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
333 | | { |
334 | | a1 = (OBAtom*)_bgn; |
335 | | a2 = (OBAtom*)_end; |
336 | | } |
337 | | |
338 | | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
339 | | { |
340 | | a1 = (OBAtom*)_end; |
341 | | a2 = (OBAtom*)_bgn; |
342 | | } |
343 | | |
344 | | if (!a1 || !a2) |
345 | | return(false); |
346 | | if (GetBondOrder() != 1) |
347 | | return(false); |
348 | | |
349 | | OBBond *bond; |
350 | | vector<OBBond*>::iterator i; |
351 | | for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i)) |
352 | | if (bond->IsCarbonyl()) |
353 | | return(true); |
354 | | |
355 | | return(false); |
356 | | } |
357 | | |
358 | | bool OBBond::IsPrimaryAmide() |
359 | | { |
360 | | OBAtom *a1,*a2; |
361 | | a1 = a2 = NULL; |
362 | | |
363 | | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
364 | | { |
365 | | a1 = (OBAtom*)_bgn; |
366 | | a2 = (OBAtom*)_end; |
367 | | } |
368 | | |
369 | | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
370 | | { |
371 | | a1 = (OBAtom*)_end; |
372 | | a2 = (OBAtom*)_bgn; |
373 | | } |
374 | | |
375 | | if (!a1 || !a2) |
376 | | return(false); |
377 | | if (GetBondOrder() != 1) |
378 | | return(false); |
379 | | |
380 | | OBBond *bond; |
381 | | vector<OBBond*>::iterator i; |
382 | | for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i)) |
383 | | if (bond->IsCarbonyl()) |
384 | | if (a2->GetHvyDegree() == 2) |
385 | | return(true); |
386 | | |
387 | | return(false); |
388 | | } |
389 | | |
390 | | bool OBBond::IsSecondaryAmide() |
391 | | { |
392 | | OBAtom *a1,*a2; |
393 | | a1 = a2 = NULL; |
394 | | |
395 | | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7) |
396 | | { |
397 | | a1 = (OBAtom*)_bgn; |
398 | | a2 = (OBAtom*)_end; |
399 | | } |
400 | | |
401 | | if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6) |
402 | | { |
403 | | a1 = (OBAtom*)_end; |
404 | | a2 = (OBAtom*)_bgn; |
405 | | } |
406 | | |
407 | | if (!a1 || !a2) |
408 | | return(false); |
409 | | if (GetBondOrder() != 1) |
410 | | return(false); |
411 | | |
412 | | OBBond *bond; |
413 | | vector<OBBond*>::iterator i; |
414 | | for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i)) |
415 | | if (bond->IsCarbonyl()) |
416 | | if (a2->GetHvyDegree() == 3) |
417 | | return(true); |
418 | | |
419 | | return(false); |
420 | | } |
421 | | */ |
422 | | |
423 | | bool OBBond::IsEster() |
424 | 0 | { |
425 | 0 | OBAtom *a1,*a2; |
426 | 0 | a1 = a2 = nullptr; |
427 | |
|
428 | 0 | if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 8) |
429 | 0 | { |
430 | 0 | a1 = (OBAtom*)_bgn; |
431 | 0 | a2 = (OBAtom*)_end; |
432 | 0 | } |
433 | |
|
434 | 0 | if (_bgn->GetAtomicNum() == 8 && _end->GetAtomicNum() == 6) |
435 | 0 | { |
436 | 0 | a1 = (OBAtom*)_end; |
437 | 0 | a2 = (OBAtom*)_bgn; |
438 | 0 | } |
439 | |
|
440 | 0 | if (!a1 || !a2) |
441 | 0 | return(false); |
442 | 0 | if (GetBondOrder() != 1) |
443 | 0 | return(false); |
444 | | |
445 | 0 | OBBond *bond; |
446 | 0 | vector<OBBond*>::iterator i; |
447 | 0 | for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i)) |
448 | 0 | if (bond->IsCarbonyl()) |
449 | 0 | return(true); |
450 | | |
451 | 0 | return(false); |
452 | 0 | } |
453 | | |
454 | | bool OBBond::IsCarbonyl() |
455 | 0 | { |
456 | 0 | if (GetBondOrder() != 2) |
457 | 0 | return(false); |
458 | | |
459 | 0 | if ((_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 8) || |
460 | 0 | (_bgn->GetAtomicNum() == 8 && _end->GetAtomicNum() == 6)) |
461 | 0 | return(true); |
462 | | |
463 | 0 | return(false); |
464 | 0 | } |
465 | | |
466 | | bool OBBond::IsAromatic() const |
467 | 452M | { |
468 | 452M | OBMol *mol = ((OBBond*)this)->GetParent(); |
469 | 452M | if (!mol->HasAromaticPerceived()) |
470 | 10.3k | aromtyper.AssignAromaticFlags(*mol); |
471 | | |
472 | 452M | if (this->HasFlag(OB_AROMATIC_BOND)) |
473 | 225M | return true; |
474 | | |
475 | 226M | return false; |
476 | 452M | } |
477 | | |
478 | | /*! This method checks if the geometry around this bond looks unsaturated |
479 | | by measuring the torsion angles formed by all connected atoms X-start=end-Y |
480 | | and checking that they are close to 0 or 180 degrees */ |
481 | | bool OBBond::IsDoubleBondGeometry() |
482 | 1.17k | { |
483 | 1.17k | double torsion; |
484 | 1.17k | OBAtom *nbrStart,*nbrEnd; |
485 | 1.17k | vector<OBBond*>::iterator i,j; |
486 | | // We concentrate on sp2 atoms with valence up to 3 and ignore the rest (like sp1 or S,P) |
487 | | // As this is called from PerceiveBondOrders, GetHyb() may still be undefined. |
488 | 1.17k | if (_bgn->GetHyb()==1 || _bgn->GetExplicitDegree()>3|| |
489 | 1.17k | _end->GetHyb()==1 || _end->GetExplicitDegree()>3) |
490 | 0 | return(true); |
491 | | |
492 | 2.75k | for (nbrStart = static_cast<OBAtom*>(_bgn)->BeginNbrAtom(i); nbrStart; |
493 | 1.57k | nbrStart = static_cast<OBAtom*>(_bgn)->NextNbrAtom(i)) |
494 | 1.59k | { |
495 | 1.59k | if (nbrStart != _end) |
496 | 436 | { |
497 | 436 | for (nbrEnd = static_cast<OBAtom*>(_end)->BeginNbrAtom(j); |
498 | 1.22k | nbrEnd; nbrEnd = static_cast<OBAtom*>(_end)->NextNbrAtom(j)) |
499 | 801 | { |
500 | 801 | if (nbrEnd != _bgn) |
501 | 378 | { |
502 | 378 | torsion=fabs(_parent->GetTorsion(nbrStart, _bgn, _end, nbrEnd)); |
503 | | |
504 | | // >12&&<168 not enough |
505 | 378 | if (torsion > 15.0 && torsion < 160.0) |
506 | 16 | { |
507 | | // Geometry does not match a double bond |
508 | 16 | return(false); |
509 | 16 | } |
510 | | |
511 | 378 | } |
512 | 801 | } // end loop for neighbors of end |
513 | 436 | } |
514 | 1.59k | } // end loop for neighbors of start |
515 | 1.15k | return(true); |
516 | 1.17k | } |
517 | | |
518 | | bool OBBond::IsInRing() const |
519 | 54.3M | { |
520 | 54.3M | OBMol *mol = ((OBBond*)this)->GetParent(); |
521 | 54.3M | if (!mol->HasRingAtomsAndBondsPerceived()) |
522 | 10.7k | mol->FindRingAtomsAndBonds(); |
523 | | |
524 | 54.3M | if (((OBBond*)this)->HasFlag(OB_RING_BOND)) |
525 | 35.4M | return true; |
526 | | |
527 | 18.9M | return false; |
528 | 54.3M | } |
529 | | |
530 | | // Adapted from OBAtom::IsInRingSize() |
531 | | OBRing* OBBond::FindSmallestRing() const |
532 | 668k | { |
533 | 668k | vector<OBRing*> rlist; |
534 | 668k | vector<OBRing*>::iterator i; |
535 | | |
536 | 668k | OBMol *mol = (OBMol*)((OBBond*)this)->GetParent(); |
537 | | |
538 | 668k | rlist = mol->GetSSSR(); |
539 | 668k | OBRing* result = nullptr; |
540 | 668k | size_t min_size = UINT_MAX; |
541 | 20.5M | for (i = rlist.begin();i != rlist.end();++i) { |
542 | 19.8M | if ((*i)->IsMember((OBBond*)this) && (*i)->Size() < min_size) { |
543 | 217k | min_size = (*i)->Size(); |
544 | 217k | result = *i; |
545 | 217k | } |
546 | 19.8M | } |
547 | 668k | return result; |
548 | 668k | } |
549 | | |
550 | | bool OBBond::IsClosure() |
551 | 139M | { |
552 | 139M | OBMol *mol = (OBMol*)GetParent(); |
553 | 139M | if (!mol) |
554 | 0 | return false; |
555 | 139M | if (!mol->HasClosureBondsPerceived()) |
556 | 0 | mol->FindRingAtomsAndBonds(); |
557 | 139M | return HasFlag(OB_CLOSURE_BOND); |
558 | 139M | } |
559 | | |
560 | | //! \return a "corrected" bonding radius based on the hybridization. |
561 | | //! Scales the covalent radius by 0.95 for sp2 and 0.90 for sp hybrids |
562 | | static double CorrectedBondRad(unsigned int elem, unsigned int hyb) |
563 | 0 | { |
564 | 0 | double rad = OBElements::GetCovalentRad(elem); |
565 | 0 | switch (hyb) { |
566 | 0 | case 2: |
567 | 0 | return rad * 0.95; |
568 | 0 | case 1: |
569 | 0 | return rad * 0.90; |
570 | 0 | default: |
571 | 0 | return rad; |
572 | 0 | } |
573 | 0 | } |
574 | | |
575 | | double OBBond::GetEquibLength() const |
576 | 0 | { |
577 | 0 | const OBAtom *begin, *end; |
578 | |
|
579 | 0 | begin = GetBeginAtom(); |
580 | 0 | end = GetEndAtom(); |
581 | 0 | double length = CorrectedBondRad(begin->GetAtomicNum(), begin->GetHyb()) |
582 | 0 | + CorrectedBondRad(end->GetAtomicNum(), end->GetHyb()); |
583 | |
|
584 | 0 | if (IsAromatic()) |
585 | 0 | return length * 0.93; |
586 | | |
587 | 0 | switch (_order) { |
588 | 0 | case 3: |
589 | 0 | return length * 0.87; |
590 | 0 | case 2: |
591 | 0 | return length * 0.91; |
592 | 0 | } |
593 | 0 | return length; |
594 | 0 | } |
595 | | |
596 | | double OBBond::GetLength() const |
597 | 118M | { |
598 | 118M | double d2; |
599 | 118M | const OBAtom *begin, *end; |
600 | 118M | begin = GetBeginAtom(); |
601 | 118M | end = GetEndAtom(); |
602 | | |
603 | 118M | if (!IsPeriodic()) |
604 | 118M | { |
605 | 118M | d2 = SQUARE(begin->GetX() - end->GetX()); |
606 | 118M | d2 += SQUARE(begin->GetY() - end->GetY()); |
607 | 118M | d2 += SQUARE(begin->GetZ() - end->GetZ()); |
608 | 118M | return(sqrt(d2)); |
609 | 118M | } |
610 | 0 | else |
611 | 0 | { |
612 | 0 | OBMol *mol = (OBMol*)((OBBond*)this)->GetParent(); |
613 | 0 | OBUnitCell *box = (OBUnitCell*)mol->GetData(OBGenericDataType::UnitCell); |
614 | 0 | return (box->MinimumImageCartesian(begin->GetVector() - end->GetVector())).length(); |
615 | 0 | } |
616 | 118M | } |
617 | | |
618 | | /*Now in OBBase |
619 | | // OBGenericData methods |
620 | | bool OBBond::HasData(string &s) |
621 | | //returns true if the generic attribute/value pair exists |
622 | | { |
623 | | if (_vdata.empty()) |
624 | | return(false); |
625 | | |
626 | | vector<OBGenericData*>::iterator i; |
627 | | |
628 | | for (i = _vdata.begin();i != _vdata.end();++i) |
629 | | if ((*i)->GetAttribute() == s) |
630 | | return(true); |
631 | | |
632 | | return(false); |
633 | | } |
634 | | |
635 | | bool OBBond::HasData(const char *s) |
636 | | //returns true if the generic attribute/value pair exists |
637 | | { |
638 | | if (_vdata.empty()) |
639 | | return(false); |
640 | | |
641 | | vector<OBGenericData*>::iterator i; |
642 | | |
643 | | for (i = _vdata.begin();i != _vdata.end();++i) |
644 | | if ((*i)->GetAttribute() == s) |
645 | | return(true); |
646 | | |
647 | | return(false); |
648 | | } |
649 | | |
650 | | bool OBBond::HasData(unsigned int dt) |
651 | | //returns true if the generic attribute/value pair exists |
652 | | { |
653 | | if (_vdata.empty()) |
654 | | return(false); |
655 | | |
656 | | vector<OBGenericData*>::iterator i; |
657 | | |
658 | | for (i = _vdata.begin();i != _vdata.end();++i) |
659 | | if ((*i)->GetDataType() == dt) |
660 | | return(true); |
661 | | |
662 | | return(false); |
663 | | } |
664 | | |
665 | | OBGenericData *OBBond::GetData(string &s) |
666 | | //returns the value given an attribute |
667 | | { |
668 | | vector<OBGenericData*>::iterator i; |
669 | | |
670 | | for (i = _vdata.begin();i != _vdata.end();++i) |
671 | | if ((*i)->GetAttribute() == s) |
672 | | return(*i); |
673 | | |
674 | | return(NULL); |
675 | | } |
676 | | |
677 | | OBGenericData *OBBond::GetData(const char *s) |
678 | | //returns the value given an attribute |
679 | | { |
680 | | vector<OBGenericData*>::iterator i; |
681 | | |
682 | | for (i = _vdata.begin();i != _vdata.end();++i) |
683 | | if ((*i)->GetAttribute() == s) |
684 | | return(*i); |
685 | | |
686 | | return(NULL); |
687 | | } |
688 | | |
689 | | OBGenericData *OBBond::GetData(unsigned int dt) |
690 | | { |
691 | | vector<OBGenericData*>::iterator i; |
692 | | for (i = _vdata.begin();i != _vdata.end();++i) |
693 | | if ((*i)->GetDataType() == dt) |
694 | | return(*i); |
695 | | return(NULL); |
696 | | } |
697 | | |
698 | | void OBBond::DeleteData(unsigned int dt) |
699 | | { |
700 | | vector<OBGenericData*> vdata; |
701 | | vector<OBGenericData*>::iterator i; |
702 | | for (i = _vdata.begin();i != _vdata.end();++i) |
703 | | if ((*i)->GetDataType() == dt) |
704 | | delete *i; |
705 | | else |
706 | | vdata.push_back(*i); |
707 | | _vdata = vdata; |
708 | | } |
709 | | |
710 | | void OBBond::DeleteData(vector<OBGenericData*> &vg) |
711 | | { |
712 | | vector<OBGenericData*> vdata; |
713 | | vector<OBGenericData*>::iterator i,j; |
714 | | |
715 | | bool del; |
716 | | for (i = _vdata.begin();i != _vdata.end();++i) |
717 | | { |
718 | | del = false; |
719 | | for (j = vg.begin();j != vg.end();++j) |
720 | | if (*i == *j) |
721 | | { |
722 | | del = true; |
723 | | break; |
724 | | } |
725 | | if (del) |
726 | | delete *i; |
727 | | else |
728 | | vdata.push_back(*i); |
729 | | } |
730 | | _vdata = vdata; |
731 | | } |
732 | | |
733 | | void OBBond::DeleteData(OBGenericData *gd) |
734 | | { |
735 | | vector<OBGenericData*>::iterator i; |
736 | | for (i = _vdata.begin();i != _vdata.end();++i) |
737 | | if (*i == gd) |
738 | | { |
739 | | delete *i; |
740 | | _vdata.erase(i); |
741 | | } |
742 | | |
743 | | } |
744 | | */ |
745 | | |
746 | | } // end namespace OpenBabel |
747 | | |
748 | | //! \file bond.cpp |
749 | | //! \brief Handle OBBond class |