1 package Bond; 2 # 3 # $RCSfile: Bond.pm,v $ 4 # $Date: 2015/02/28 20:47:02 $ 5 # $Revision: 1.40 $ 6 # 7 # Author: Manish Sud <msud@san.rr.com> 8 # 9 # Copyright (C) 2015 Manish Sud. All rights reserved. 10 # 11 # This file is part of MayaChemTools. 12 # 13 # MayaChemTools is free software; you can redistribute it and/or modify it under 14 # the terms of the GNU Lesser General Public License as published by the Free 15 # Software Foundation; either version 3 of the License, or (at your option) any 16 # later version. 17 # 18 # MayaChemTools is distributed in the hope that it will be useful, but without 19 # any warranty; without even the implied warranty of merchantability of fitness 20 # for a particular purpose. See the GNU Lesser General Public License for more 21 # details. 22 # 23 # You should have received a copy of the GNU Lesser General Public License 24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 26 # Boston, MA, 02111-1307, USA. 27 # 28 29 use strict; 30 use Carp; 31 use Exporter; 32 use Storable (); 33 use Scalar::Util (); 34 use ObjectProperty; 35 36 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 37 38 @ISA = qw(ObjectProperty Exporter); 39 @EXPORT = qw(); 40 @EXPORT_OK = qw(); 41 42 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 43 44 # Setup class variables... 45 my($ClassName, $ObjectID); 46 _InitializeClass(); 47 48 # Overload Perl functions... 49 use overload '""' => 'StringifyBond'; 50 51 # Class constructor... 52 sub new { 53 my($Class, %NamesAndValues) = @_; 54 55 # Initialize object... 56 my $This = {}; 57 bless $This, ref($Class) || $Class; 58 $This->_InitializeBond(); 59 60 $This->_InitializeBondProperties(%NamesAndValues); 61 62 return $This; 63 } 64 65 # Initialize object data... 66 # 67 sub _InitializeBond { 68 my($This) = @_; 69 my($ObjectID) = _GetNewObjectID(); 70 71 # All other property names and values along with all Set/Get<PropertyName> methods 72 # are implemented on-demand using ObjectProperty class. 73 $This->{ID} = $ObjectID; 74 75 # Bond from and to atoms indicate begining and ending bond atoms... 76 $This->{BondFromAtom} = undef; 77 $This->{BondToAtom} = undef; 78 79 $This->{BondOrder} = ''; 80 $This->{BondType} = ''; 81 $This->{BondStereochemistry} = ''; 82 } 83 84 # Initialize class ... 85 sub _InitializeClass { 86 #Class name... 87 $ClassName = __PACKAGE__; 88 89 # ID to keep track of objects... 90 $ObjectID = 0; 91 } 92 93 # Initialize bond properties... 94 sub _InitializeBondProperties { 95 my($This, %NamesAndValues) = @_; 96 97 my($Name, $Value, $MethodName); 98 while (($Name, $Value) = each %NamesAndValues) { 99 $MethodName = "Set${Name}"; 100 $This->$MethodName($Value); 101 } 102 103 if (!exists $NamesAndValues{'Atoms'}) { 104 carp "Warning: ${ClassName}->new: Bond object instantiated without specifying atoms list..."; 105 } 106 if (!exists $NamesAndValues{'BondOrder'}) { 107 carp "Warning: ${ClassName}->new: Bond object instantiated without setting bond order..."; 108 } 109 return $This; 110 } 111 112 # Setup an explicit SetID method to block setting of ID by AUTOLOAD function... 113 sub SetID { 114 my($This, $Value) = @_; 115 116 carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking..."; 117 118 return $This; 119 } 120 121 # Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function... 122 sub SetMolecule { 123 my($This, $Value) = @_; 124 125 carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking..."; 126 127 return $This; 128 } 129 130 # Assign bond to molecule... 131 sub _SetMolecule { 132 my($This, $Molecule) = @_; 133 134 $This->{Molecule} = $Molecule; 135 136 # Weaken the reference to disable increment of reference count; otherwise, 137 # it it becomes a circular reference and destruction of Molecule object doesn't 138 # get initiated which in turn disables destruction of bond object. 139 # 140 Scalar::Util::weaken($This->{Molecule}); 141 142 return $This; 143 } 144 145 # Set bond atoms... 146 sub SetAtoms { 147 my($This, @Values) = @_; 148 149 if (!@Values) { 150 croak "Error: ${ClassName}->SetAtoms: No atoms specified..."; 151 } 152 153 my($FirstValue, $TypeOfFirstValue, $Atom1, $Atom2, $AtomID1, $AtomID2); 154 $FirstValue = $Values[0]; 155 $TypeOfFirstValue = ref $FirstValue; 156 157 if ($TypeOfFirstValue =~ /^ARRAY/) { 158 # Initialize using array refernce... 159 if (@{$FirstValue} != 2) { 160 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 161 } 162 ($Atom1, $Atom2) = @{$FirstValue}; 163 } 164 else { 165 # It's a list of values... 166 if (@Values != 2) { 167 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 168 } 169 ($Atom1, $Atom2) = @Values; 170 } 171 172 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); 173 if ($AtomID1 == $AtomID2) { 174 croak "Warning: ${ClassName}->SetAtoms: Can't specify same atoms to create a bond..."; 175 } 176 177 $This->{BondFromAtom} = $Atom1; 178 $This->{BondToAtom} = $Atom2; 179 180 return $This; 181 } 182 183 # Get bond atoms as array. In scalar context, return number of atoms involved in 184 # bond... 185 # 186 sub GetAtoms { 187 my($This) = @_; 188 189 return wantarray ? ($This->{BondFromAtom}, $This->{BondToAtom}) : 2; 190 } 191 192 # Get atom bonded to specified atom... 193 sub GetBondedAtom { 194 my($This, $Atom) = @_; 195 my($Atom1, $Atom2, $AtomID1, $AtomID2, $AtomID); 196 197 ($Atom1, $Atom2) = $This->GetAtoms(); 198 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); $AtomID = $Atom->GetID(); 199 200 return ($AtomID1 == $AtomID) ? $Atom2 : (($AtomID2 == $AtomID) ? $Atom1 : undef) ; 201 } 202 203 # Get common atom between two bonds... 204 sub GetCommonAtom { 205 my($This, $Other) = @_; 206 my($Atom1, $Atom2, $AtomID1, $AtomID2, $OtherAtom1, $OtherAtom2, $OtherAtomID1, $OtherAtomID2); 207 208 ($Atom1, $Atom2) = $This->GetAtoms(); 209 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); 210 211 ($OtherAtom1, $OtherAtom2) = $Other->GetAtoms(); 212 $OtherAtomID1 = $OtherAtom1->GetID(); $OtherAtomID2 = $OtherAtom2->GetID(); 213 214 return ($AtomID1 == $OtherAtomID1 || $AtomID1 == $OtherAtomID2) ? $Atom1 : (($AtomID2 == $OtherAtomID1 || $AtomID2 == $OtherAtomID2) ? $Atom2 : undef) ; 215 } 216 217 # Get bond from atom indicating begining atom of a bond... 218 sub GetBondFromAtom { 219 my($This) = @_; 220 221 return $This->{BondFromAtom}; 222 } 223 224 # Get begin bond atom... 225 sub GetBondBeginAtom { 226 my($This) = @_; 227 228 return $This->GetBondFromAtom(); 229 } 230 231 # Get bond to atom indicating ending atom of a bond... 232 sub GetBondToAtom { 233 my($This) = @_; 234 235 return $This->{BondToAtom}; 236 } 237 238 # Get begin bond atom... 239 sub GetBondEndAtom { 240 my($This) = @_; 241 242 return $This->GetBondToAtom(); 243 } 244 245 # Switch bond from and to atoms... 246 sub SwitchBondFromAndToAtoms { 247 my($This) = @_; 248 my($FromAtom, $ToAtom); 249 250 ($FromAtom, $ToAtom) = $This->GetAtoms(); 251 252 $This->{BondFromAtom} = $ToAtom; 253 $This->{BondToAtom} = $FromAtom; 254 255 return $This; 256 } 257 258 # Set bond order... 259 # 260 # Possible BondOrder are: 0 = None, 1 = Single, 1.5 = Aromatic, 2 = Double, 3 = Triple, 4 = Quadruple, 261 # 5 = Quintuple, 6 = Sextuple, 7 = Septuple 262 # 263 # Possible BondType for different BondOrders are: 264 # 265 # 0 : None, Ionic, Unspecified 266 # 1 : Single, Dative, Coordinate, SingleOrDouble, SingleOrAromatic, Tautomeric 267 # 1.5 : Aromatic, Resonance, SingleOrAromatic, DoubleOrAromatic 268 # 2 : Double, Tautomeric, SingleOrDouble, DoubleOrAromatic 269 # 3 : Triple 270 # 4 : Quadruple 271 # 5 : Quintuple 272 # 6 : Sextuple 273 # 7 : Septuple 274 # 275 # Note: BondType Any is valid for all BondOrders. 276 # 277 # Possible BondStereochemistry values for different BondOrders are: 278 # 279 # 0 : None, Unspecified 280 # 1 : Wedge, Up, Hash, Down, Wavy, WedgeOrHash, UpOrDown, Upward, Downward, None, Unspecified 281 # 2 : Cis, Trans, Z, E, DoubleCross, CisOrTrans, None, Unspecified 282 # 283 # Notes: 284 # . BondType property is automatically assigned using default BondType values for 285 # specified BondOrder. 286 # . BondType values can also be explicit set. 287 # . To make bonds aromatic in a ring, explicitly set "Aromatic" property for bond/atoms and make sure 288 # appropriate BondOrder values are assigned. 289 # . Dative or coordinate bond types are treated as single bond types with explicit formal charge 290 # of + and - on first and second bond atoms. 291 # 292 sub SetBondOrder { 293 my($This, $BondOrder) = @_; 294 295 if ($BondOrder !~ /^(0|1|1.5|2|3|4|5|6|7)$/) { 296 croak "Error: ${ClassName}->SetBondOrder: BondOrder value $BondOrder is not valid. Supported values: 0, 1, 1.5, 2, 3, 4, 5, 6, 7"; 297 } 298 299 # Set bond order and type... 300 my($BondType); 301 302 BONDORDER: { 303 if ($BondOrder == 1) {$BondType = 'Single'; last BONDORDER; } 304 if ($BondOrder == 1.5) {$BondType = 'Aromatic'; last BONDORDER; } 305 if ($BondOrder == 2) {$BondType = 'Double'; last BONDORDER; } 306 if ($BondOrder == 3) {$BondType = 'Triple'; last BONDORDER; } 307 if ($BondOrder == 4) {$BondType = 'Quadruple'; last BONDORDER; } 308 if ($BondOrder == 5) {$BondType = 'Quintuple'; last BONDORDER; } 309 if ($BondOrder == 6) {$BondType = 'Sextuple'; last BONDORDER; } 310 if ($BondOrder == 7) {$BondType = 'Septuple'; last BONDORDER; } 311 $BondType = ''; 312 $BondOrder = 0; 313 } 314 $This->{BondType} = $BondType; 315 $This->{BondOrder} = $BondOrder; 316 317 return $This; 318 319 } 320 321 # Set bond type for a specific bond... 322 # 323 sub SetBondType { 324 my($This, $BondType) = @_; 325 326 if ($BondType !~ /^(None|Ionic|Unspecified|Single|Dative|Coordinate|SingleOrDouble|SingleOrAromatic|Aromatic|Tautomeric|Resonance|DoubleOrAromatic|Double|Triple|Quadruple|Any)$/i) { 327 croak "Error: ${ClassName}->SetBondType: BondType value $BondType is not valid. Supported values: None, Ionic, Unspecified, Single, Dative, Coordinate, SingleOrDouble, SingleOrAromatic, Aromatic, Tautomeric, Resonance, DoubleOrAromatic, Double, Triple, Quadruple, Any..."; 328 } 329 330 # Make sure its a valid BondType value for BondOrder... 331 my($BondOrder, $ValidBondType); 332 333 $ValidBondType = 0; 334 $BondOrder = $This->{BondOrder}; 335 336 BONDORDER: { 337 if ($BondOrder == 0 && $BondType =~ /^(None|Ionic|Unspecified|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 338 if ($BondOrder == 1 && $BondType =~ /^(Single|Dative|Coordinate|SingleOrDouble|SingleOrAromatic|Tautomeric|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 339 if ($BondOrder == 1.5 && $BondType =~ /^(Aromatic|Resonance|SingleOrAromatic|DoubleOrAromatic|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 340 if ($BondOrder == 2 && $BondType =~ /^(Double|SingleOrDouble|DoubleOrAromatic|Tautomeric|Any)$/i ) {$ValidBondType = 1; last BONDORDER; } 341 if ($BondOrder == 3 && $BondType =~ /^(Triple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 342 if ($BondOrder == 4 && $BondType =~ /^(Quadruple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 343 if ($BondOrder == 5 && $BondType =~ /^(Quintuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 344 if ($BondOrder == 6 && $BondType =~ /^(Sextuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 345 if ($BondOrder == 7 && $BondType =~ /^(Septuple|Any)$/i) {$ValidBondType = 1; last BONDORDER; } 346 $ValidBondType = 0; 347 } 348 349 if (!$ValidBondType) { 350 carp "Warning: ${ClassName}->SetBondType: Assigning invalid BondType value, $BondType, for BondOrder $BondOrder..."; 351 } 352 353 $This->{BondType} = $BondType; 354 355 # Set explicit formal charge for atoms involved in Dative or coordinate bonds... 356 if ($BondType =~ /^(Dative|Coordinate)$/i) { 357 my($Atom1, $Atom2) = $This->GetAtoms(); 358 $Atom1->SetFormalCharge('1'); 359 $Atom2->SetFormalCharge('-1'); 360 } 361 362 return $This; 363 } 364 365 # Set bond stereochemistry... 366 # 367 # Single bond stereochemistry: 368 # 369 # None, Unspecified: Not a stereo bond or unspecified 370 # 371 # Wedge, Up : Wedge end pointing up 372 # Hash, Down: Wedge end pointing down 373 # Wavy, WedgeOrHash, UpOrDown: Wedge end up or down 374 # 375 # Note: Wedge starts at begin atom of bond making wedge pointed end always at this 376 # atom. 377 # 378 # Upward: Single bond around cis/trans double bonds pointing upward 379 # Downward: Single bond around cis/trans double bonds pointing upward 380 # 381 # Note: Upward/downward bonds start at atoms involved in cis/trans double bond. 382 # 383 # Double bond stereochemistry: 384 # 385 # None, Unspecified: Not a stereo bond or unspecified 386 # 387 # Z, cis: Similar groups on same side of double bond 388 # E, trans: Similar groups on different side of double bond 389 # 390 # CisOrTrans, DoubleCross: cis or trans 391 # 392 sub SetBondStereochemistry { 393 my($This, $BondStereochemistry) = @_; 394 395 if ($BondStereochemistry !~ /^(None|Unspecified|Wedge|Hash|Up|Down|Wavy|WedgeOrHash|UpOrDown|Upward|Downward|Cis|Trans|Z|E|DoubleCross|CisOrTrans)$/i) { 396 croak "Error: ${ClassName}->SetBondStereochemistry: BondStereochemistry value $BondStereochemistry is not valid. Supported values: None, Unspecified, Wedge, Hash, Up, Down, Wavy, WedgeOrHash, UpOrDown, Upward, Downward, Cis, Trans, Z, E, DoubleCross, CisOrTrans..."; 397 } 398 399 # Make sure its a valid BondStereochemistry value for BondOrder... 400 my($BondOrder, $ValidBondType); 401 402 $ValidBondType = 0; 403 $BondOrder = $This->{BondOrder}; 404 405 BONDORDER: { 406 if ($BondOrder == 0 && $BondStereochemistry =~ /^(None|Unspecified)$/i) {$ValidBondType = 1; last BONDORDER; } 407 if ($BondOrder == 1 && $BondStereochemistry =~ /^(Wedge|Hash|Up|Down|Wavy|WedgeOrHash|UpOrDown|Upward|Downward|None|Unspecified)$/i) {$ValidBondType = 1; last BONDORDER; } 408 if ($BondOrder == 2 && $BondStereochemistry =~ /^(Cis|Trans|Z|E|DoubleCross|CisOrTrans|None|Unspecified)$/i ) {$ValidBondType = 1; last BONDORDER; } 409 $ValidBondType = 0; 410 } 411 412 if (!$ValidBondType) { 413 carp "Warning: ${ClassName}->SetBondStereochemistry: Assigning invalid BondStereochemistry value, $BondStereochemistry, for BondOrder $BondOrder..."; 414 } 415 416 $This->{BondStereochemistry} = $BondStereochemistry; 417 418 return $This; 419 } 420 421 # Is it a single bond? 422 sub IsSingle { 423 my($This) = @_; 424 425 return ($This->{BondOrder} == 1) ? 1 : 0; 426 } 427 428 # Is it a double bond? 429 sub IsDouble { 430 my($This) = @_; 431 432 return ($This->{BondOrder} == 2) ? 1 : 0; 433 } 434 435 # Is it a triple bond? 436 sub IsTriple { 437 my($This) = @_; 438 439 return ($This->{BondOrder} == 3) ? 1 : 0; 440 } 441 442 # Is it a quadruple bond? 443 sub IsQuadruple { 444 my($This) = @_; 445 446 return ($This->{BondOrder} == 4) ? 1 : 0; 447 } 448 449 # Is aromatic property set for the bond? 450 sub IsAromatic { 451 my($This) = @_; 452 my($Aromatic); 453 454 $Aromatic = $This->GetAromatic(); 455 456 return ((defined($Aromatic) && $Aromatic) || $This->{BondOrder} == 1.5) ? 1 : 0; 457 } 458 459 # Is it a quintuple bond? 460 sub IsQuintuple { 461 my($This) = @_; 462 463 return ($This->{BondOrder} == 5) ? 1 : 0; 464 } 465 466 # Is it a sextuple bond? 467 sub IsSextuple { 468 my($This) = @_; 469 470 return ($This->{BondOrder} == 6) ? 1 : 0; 471 } 472 473 # Is bond type specified? 474 sub IsBondTypeSpecified { 475 my($This) = @_; 476 477 return ($This->{BondType} && $This->{BondType} !~ /^(None|Unspecified)$/i) ? 1 : 0; 478 } 479 480 # Is it a dative or coordinate bond? 481 sub IsDative { 482 my($This) = @_; 483 484 return ($This->{BondType} =~ /^(Dative|Coordinate)$/i) ? 1 : 0; 485 } 486 487 # Is it a dative or coordinate bond? 488 sub IsCoordinate { 489 my($This) = @_; 490 491 return $This->IsDative(); 492 } 493 494 # Is it a ionic bond? 495 sub IsIonic { 496 my($This) = @_; 497 498 return ($This->{BondType} =~ /^Ionic$/i) ? 1 : 0; 499 } 500 501 # Is it a tautomeric bond? 502 sub IsTautomeric { 503 my($This) = @_; 504 505 return ($This->{BondType} =~ /^Tautomeric$/i) ? 1 : 0; 506 } 507 508 # Is bond stereochemistry specified? 509 sub IsBondStereochemistrySpecified { 510 my($This) = @_; 511 512 return ($This->{BondStereochemistry} && $This->{BondStereochemistry} !~ /^(None|Unspecified)$/i) ? 1 : 0; 513 } 514 515 # Is it a Wedge or Up single bond? 516 sub IsWedge { 517 my($This) = @_; 518 519 return $This->IsUp(); 520 } 521 522 # Is it a Wedge or Up single bond? 523 sub IsUp { 524 my($This) = @_; 525 526 return ($This->{BondStereochemistry} =~ /^(Wedge|Up)$/i) ? 1 : 0; 527 } 528 529 # Is it a Hash or Down single bond? 530 sub IsHash { 531 my($This) = @_; 532 533 return $This->IsDown(); 534 } 535 536 # Is it a Hash or Down single bond? 537 sub IsDown { 538 my($This) = @_; 539 540 return ($This->{BondStereochemistry} =~ /^(Hash|Down)$/i) ? 1 : 0; 541 } 542 543 # Is it a Wavy, WedgeOrHash or UpOrDown single bond? 544 sub IsWedgeOrHash { 545 my($This) = @_; 546 547 return $This->IsUpOrDown(); 548 } 549 550 # Is it a Wavy, WedgeOrHash or UpOrDown single bond? 551 sub IsUpOrDown { 552 my($This) = @_; 553 554 return ($This->{BondStereochemistry} =~ /^(Wavy|WedgeOrHash|UpOrDown)$/i) ? 1 : 0; 555 } 556 557 # Is it a upward single bond? 558 sub IsUpward { 559 my($This) = @_; 560 561 return ($This->{BondStereochemistry} =~ /^Upward$/i) ? 1 : 0; 562 } 563 564 # Is it a Downward single bond? 565 sub IsDownward { 566 my($This) = @_; 567 568 return ($This->{BondStereochemistry} =~ /^Downward$/i) ? 1 : 0; 569 } 570 # Is it a cis or Z double bond? 571 sub IsCis { 572 my($This) = @_; 573 574 return ($This->{BondStereochemistry} =~ /^(Cis|Z)$/i) ? 1 : 0; 575 } 576 577 # Is it a trans or E double bond? 578 sub IsTrans { 579 my($This) = @_; 580 581 return ($This->{BondStereochemistry} =~ /^(Trans|E)$/i) ? 1 : 0; 582 } 583 584 # Is it a cis or trans double bond? 585 sub IsCisOrTrans { 586 my($This) = @_; 587 588 return ($This->{BondStereochemistry} =~ /^(CisOrTrans|DoubleCross)$/i) ? 1 : 0; 589 } 590 591 # Delete bond... 592 sub DeleteBond { 593 my($This) = @_; 594 595 # Is this atom in a molecule? 596 if (!$This->HasProperty('Molecule')) { 597 # Nothing to do... 598 return $This; 599 } 600 my($Molecule); 601 $Molecule = $This->GetProperty('Molecule'); 602 $Molecule->DeleteBond($This); 603 604 return $This; 605 } 606 607 # Copy bond and all its associated data... 608 sub Copy { 609 my($This) = @_; 610 my($Bond); 611 612 $Bond = Storable::dclone($This); 613 614 return $Bond; 615 } 616 617 # Is bond in a ring? 618 # 619 sub IsInRing { 620 my($This) = @_; 621 622 # Is this bond in a molecule? 623 if (!$This->HasProperty('Molecule')) { 624 return undef; 625 } 626 my($Molecule); 627 $Molecule = $This->GetProperty('Molecule'); 628 629 return $Molecule->_IsBondInRing($This); 630 } 631 632 # Is bond not in a ring? 633 # 634 sub IsNotInRing { 635 my($This) = @_; 636 637 # Is this bond in a molecule? 638 if (!$This->HasProperty('Molecule')) { 639 return undef; 640 } 641 my($Molecule); 642 $Molecule = $This->GetProperty('Molecule'); 643 644 return $Molecule->_IsBondNotInRing($This); 645 } 646 647 # Is bond only in one ring? 648 # 649 sub IsOnlyInOneRing { 650 my($This) = @_; 651 652 # Is this bond in a molecule? 653 if (!$This->HasProperty('Molecule')) { 654 return undef; 655 } 656 my($Molecule); 657 $Molecule = $This->GetProperty('Molecule'); 658 659 return $Molecule->_IsBondInOnlyOneRing($This); 660 } 661 662 # Is bond in a ring of specific size? 663 # 664 sub IsInRingOfSize { 665 my($This, $RingSize) = @_; 666 667 # Is this bond in a molecule? 668 if (!$This->HasProperty('Molecule')) { 669 return undef; 670 } 671 my($Molecule); 672 $Molecule = $This->GetProperty('Molecule'); 673 674 return $Molecule->_IsBondInRingOfSize($This, $RingSize); 675 } 676 677 # Get size of smallest ring containing the bond... 678 # 679 sub GetSizeOfSmallestRing { 680 my($This) = @_; 681 682 # Is this bond in a molecule? 683 if (!$This->HasProperty('Molecule')) { 684 return undef; 685 } 686 my($Molecule); 687 $Molecule = $This->GetProperty('Molecule'); 688 689 return $Molecule->_GetSizeOfSmallestBondRing($This); 690 } 691 692 # Get size of largest ring containing the bond... 693 # 694 sub GetSizeOfLargestRing { 695 my($This) = @_; 696 697 # Is this bond in a molecule? 698 if (!$This->HasProperty('Molecule')) { 699 return undef; 700 } 701 my($Molecule); 702 $Molecule = $This->GetProperty('Molecule'); 703 704 return $Molecule->_GetSizeOfLargestBondRing($This); 705 } 706 707 # Get number of rings containing the bond... 708 # 709 sub GetNumOfRings { 710 my($This) = @_; 711 712 # Is this bond in a molecule? 713 if (!$This->HasProperty('Molecule')) { 714 return undef; 715 } 716 my($Molecule); 717 $Molecule = $This->GetProperty('Molecule'); 718 719 return $Molecule->_GetNumOfBondRings($This); 720 } 721 722 # Get number of rings with odd size containing the bond... 723 # 724 sub GetNumOfRingsWithOddSize { 725 my($This) = @_; 726 727 # Is this bond in a molecule? 728 if (!$This->HasProperty('Molecule')) { 729 return undef; 730 } 731 my($Molecule); 732 $Molecule = $This->GetProperty('Molecule'); 733 734 return $Molecule->_GetNumOfBondRingsWithOddSize($This); 735 } 736 737 # Get number of rings with even size containing the bond... 738 # 739 sub GetNumOfRingsWithEvenSize { 740 my($This) = @_; 741 742 # Is this bond in a molecule? 743 if (!$This->HasProperty('Molecule')) { 744 return undef; 745 } 746 my($Molecule); 747 $Molecule = $This->GetProperty('Molecule'); 748 749 return $Molecule->_GetNumOfBondRingsWithEvenSize($This); 750 } 751 752 # Get number of rings with specified size containing the bond... 753 # 754 sub GetNumOfRingsWithSize { 755 my($This, $RingSize) = @_; 756 757 # Is this bond in a molecule? 758 if (!$This->HasProperty('Molecule')) { 759 return undef; 760 } 761 my($Molecule); 762 $Molecule = $This->GetProperty('Molecule'); 763 764 return $Molecule->_GetNumOfBondRingsWithSize($This, $RingSize); 765 } 766 767 # Get number of rings with size less than specified containing the bond... 768 # 769 sub GetNumOfRingsWithSizeLessThan { 770 my($This, $RingSize) = @_; 771 772 # Is this bond in a molecule? 773 if (!$This->HasProperty('Molecule')) { 774 return undef; 775 } 776 my($Molecule); 777 $Molecule = $This->GetProperty('Molecule'); 778 779 return $Molecule->_GetNumOfBondRingsWithSizeLessThan($This, $RingSize); 780 } 781 782 # Get number of rings with size greater than specified size containing the bond... 783 # 784 sub GetNumOfRingsWithSizeGreaterThan { 785 my($This, $RingSize) = @_; 786 787 # Is this bond in a molecule? 788 if (!$This->HasProperty('Molecule')) { 789 return undef; 790 } 791 my($Molecule); 792 $Molecule = $This->GetProperty('Molecule'); 793 794 return $Molecule->_GetNumOfBondRingsWithSizeGreaterThan($This, $RingSize); 795 } 796 797 # Get all rings as an array of references to arrays containing ring atoms... 798 # 799 sub GetRings { 800 my($This) = @_; 801 802 # Is this bond in a molecule? 803 if (!$This->HasProperty('Molecule')) { 804 return undef; 805 } 806 my($Molecule); 807 $Molecule = $This->GetProperty('Molecule'); 808 809 return $Molecule->_GetBondRings($This); 810 } 811 812 # Get smallest ring as an array containing ring atoms... 813 # 814 sub GetSmallestRing { 815 my($This) = @_; 816 817 # Is this bond in a molecule? 818 if (!$This->HasProperty('Molecule')) { 819 return undef; 820 } 821 my($Molecule); 822 $Molecule = $This->GetProperty('Molecule'); 823 824 return $Molecule->_GetSmallestBondRing($This); 825 } 826 827 # Get largest ring as an array containing ring atoms... 828 # 829 sub GetLargestRing { 830 my($This) = @_; 831 832 # Is this bond in a molecule? 833 if (!$This->HasProperty('Molecule')) { 834 return undef; 835 } 836 my($Molecule); 837 $Molecule = $This->GetProperty('Molecule'); 838 839 return $Molecule->_GetLargestBondRing($This); 840 } 841 842 # Get odd size rings an array of references to arrays containing ring atoms... 843 # 844 sub GetRingsWithOddSize { 845 my($This) = @_; 846 847 # Is this bond in a molecule? 848 if (!$This->HasProperty('Molecule')) { 849 return undef; 850 } 851 my($Molecule); 852 $Molecule = $This->GetProperty('Molecule'); 853 854 return $Molecule->_GetBondRingsWithOddSize($This); 855 } 856 857 # Get even size rings an array of references to arrays containing ring atoms... 858 # 859 sub GetRingsWithEvenSize { 860 my($This) = @_; 861 862 # Is this bond in a molecule? 863 if (!$This->HasProperty('Molecule')) { 864 return undef; 865 } 866 my($Molecule); 867 $Molecule = $This->GetProperty('Molecule'); 868 869 return $Molecule->_GetBondRingsWithEvenSize($This); 870 } 871 872 # Get rings with specified size an array of references to arrays containing ring atoms... 873 # 874 sub GetRingsWithSize { 875 my($This, $RingSize) = @_; 876 877 # Is this bond in a molecule? 878 if (!$This->HasProperty('Molecule')) { 879 return undef; 880 } 881 my($Molecule); 882 $Molecule = $This->GetProperty('Molecule'); 883 884 return $Molecule->_GetBondRingsWithSize($This, $RingSize); 885 } 886 887 # Get rings with size less than specfied size as an array of references to arrays containing ring atoms... 888 # 889 sub GetRingsWithSizeLessThan { 890 my($This, $RingSize) = @_; 891 892 # Is this bond in a molecule? 893 if (!$This->HasProperty('Molecule')) { 894 return undef; 895 } 896 my($Molecule); 897 $Molecule = $This->GetProperty('Molecule'); 898 899 return $Molecule->_GetBondRingsWithSizeLessThan($This, $RingSize); 900 } 901 902 # Get rings with size greater than specfied size as an array of references to arrays containing ring atoms... 903 # 904 sub GetRingsWithSizeGreaterThan { 905 my($This, $RingSize) = @_; 906 907 # Is this bond in a molecule? 908 if (!$This->HasProperty('Molecule')) { 909 return undef; 910 } 911 my($Molecule); 912 $Molecule = $This->GetProperty('Molecule'); 913 914 return $Molecule->_GetBondRingsWithSizeGreaterThan($This, $RingSize); 915 } 916 917 # Get next object ID... 918 sub _GetNewObjectID { 919 $ObjectID++; 920 return $ObjectID; 921 } 922 923 # Return a string containing bond and other properties... 924 sub StringifyBond { 925 my($This) = @_; 926 my($BondString, $ID, $BondOrder, $BondType, $Stereochemistry, $AtomsString, $RingBond, $AromaticBond, $NumOfRings, $Atom1, $Atom2); 927 928 $ID = $This->GetID(); 929 $BondOrder = $This->GetBondOrder(); 930 if (!defined $BondOrder) { 931 $BondOrder = "undefined"; 932 } 933 $BondType = $This->GetBondType(); 934 if (!defined $BondOrder) { 935 $BondType = "undefined"; 936 } 937 if (defined($BondOrder) && $BondOrder == 2) { 938 $Stereochemistry = $This->GetStereochemistry(); 939 if (!defined $Stereochemistry) { 940 $Stereochemistry = "undefined"; 941 } 942 } 943 $RingBond = $This->IsInRing(); 944 if (defined $RingBond) { 945 $RingBond = $RingBond ? 'Yes' : 'No'; 946 $NumOfRings = $This->GetNumOfRings(); 947 } 948 else { 949 $RingBond = 'undefined'; 950 $NumOfRings = 'undefined'; 951 } 952 953 $AromaticBond = $This->GetAromatic(); 954 if (defined $AromaticBond) { 955 $AromaticBond = $AromaticBond ? 'Yes' : 'No'; 956 } 957 else { 958 $AromaticBond = 'undefined'; 959 } 960 961 ($Atom1, $Atom2) = $This->GetAtoms(); 962 $AtomsString = "Atoms: undefined"; 963 if (defined($Atom1) && defined($Atom2)) { 964 my($Atom, $AtomID, $AtomCount, $AtomName, $AtomSymbol, $AtomicNumber, @BondAtoms); 965 @BondAtoms = (); 966 push @BondAtoms, ($Atom1, $Atom2); 967 $AtomCount = 0; 968 $AtomsString = ""; 969 for $Atom (@BondAtoms) { 970 $AtomCount++; 971 $AtomID = $Atom->GetID(); 972 $AtomName = $Atom->GetName(); 973 $AtomSymbol = $Atom->GetAtomSymbol(); 974 $AtomicNumber = $Atom->GetAtomicNumber(); 975 if ($AtomCount == 1) { 976 $AtomsString .= "FirstAtom:"; 977 } 978 else { 979 $AtomsString .= "; SecondAtom:"; 980 } 981 $AtomsString .= " [ ID: $AtomID; Name: \"$AtomName\"; AtomSymbol: \"$AtomSymbol\"; AtomicNumber: $AtomicNumber ]"; 982 } 983 } 984 $BondString = "Bond: ID: $ID; BondOrder: $BondOrder; BondType: $BondType; RingBond: $RingBond; NumOfBondRings: $NumOfRings; AromaticBond: $AromaticBond;"; 985 if (defined($BondOrder) && $BondOrder == 2) { 986 $BondString .= " Stereochemistry: $Stereochemistry;"; 987 } 988 $BondString .= " $AtomsString"; 989 990 return $BondString; 991 } 992