1 package Bond; 2 # 3 # $RCSfile: Bond.pm,v $ 4 # $Date: 2011/12/16 00:04:11 $ 5 # $Revision: 1.31 $ 6 # 7 # Author: Manish Sud <msud@san.rr.com> 8 # 9 # Copyright (C) 2004-2012 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 @{$This->{Atoms}} = (); 75 $This->{BondOrder} = ''; 76 $This->{BondType} = ''; 77 } 78 79 # Initialize class ... 80 sub _InitializeClass { 81 #Class name... 82 $ClassName = __PACKAGE__; 83 84 # ID to keep track of objects... 85 $ObjectID = 0; 86 } 87 88 # Initialize bond properties... 89 sub _InitializeBondProperties { 90 my($This, %NamesAndValues) = @_; 91 92 my($Name, $Value, $MethodName); 93 while (($Name, $Value) = each %NamesAndValues) { 94 $MethodName = "Set${Name}"; 95 $This->$MethodName($Value); 96 } 97 98 if (!exists $NamesAndValues{'Atoms'}) { 99 carp "Warning: ${ClassName}->new: Bond object instantiated without specifying atoms list..."; 100 } 101 if (!exists $NamesAndValues{'BondOrder'}) { 102 carp "Warning: ${ClassName}->new: Bond object instantiated without setting bond order..."; 103 } 104 return $This; 105 } 106 107 # Setup an explicit SetID method to block setting of ID by AUTOLOAD function... 108 sub SetID { 109 my($This, $Value) = @_; 110 111 carp "Warning: ${ClassName}->SetID: Object ID can't be changed: it's used for internal tracking..."; 112 113 return $This; 114 } 115 116 # Setup an explicit SetMolecule method to block setting of ID by AUTOLOAD function... 117 sub SetMolecule { 118 my($This, $Value) = @_; 119 120 carp "Warning: ${ClassName}->SetMolecule: Molecule property can't be changed: it's used for internal tracking..."; 121 122 return $This; 123 } 124 125 # Assign bond to molecule... 126 sub _SetMolecule { 127 my($This, $Molecule) = @_; 128 129 $This->{Molecule} = $Molecule; 130 131 # Weaken the reference to disable increment of reference count; otherwise, 132 # it it becomes a circular reference and destruction of Molecule object doesn't 133 # get initiated which in turn disables destruction of bond object. 134 # 135 Scalar::Util::weaken($This->{Molecule}); 136 137 return $This; 138 } 139 140 # Set bond atoms... 141 sub SetAtoms { 142 my($This, @Values) = @_; 143 144 if (!@Values) { 145 croak "Error: ${ClassName}->SetAtoms: No atoms specified..."; 146 } 147 148 my($FirstValue, $TypeOfFirstValue, $Atom1, $Atom2, $AtomID1, $AtomID2); 149 $FirstValue = $Values[0]; 150 $TypeOfFirstValue = ref $FirstValue; 151 152 if ($TypeOfFirstValue =~ /^ARRAY/) { 153 # Initialize using array refernce... 154 if (@{$FirstValue} != 2) { 155 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 156 } 157 ($Atom1, $Atom2) = @{$FirstValue}; 158 } 159 else { 160 # It's a list of values... 161 if (@Values != 2) { 162 croak "Warning: ${ClassName}->SetAtoms: Number of atoms specified in bond object is not equal to 2..."; 163 } 164 ($Atom1, $Atom2) = @Values; 165 push @{$This->{Atoms}}, @Values; 166 } 167 168 $AtomID1 = $Atom1->GetID(); $AtomID2 = $Atom2->GetID(); 169 if ($AtomID1 == $AtomID2) { 170 croak "Warning: ${ClassName}->SetAtoms: Can't specify same atoms to create a bond..."; 171 } 172 173 if ($AtomID1 < $AtomID2) { 174 push @{$This->{Atoms}}, ($Atom1, $Atom2); 175 } 176 else { 177 push @{$This->{Atoms}}, ($Atom2, $Atom1); 178 } 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->{Atoms}} : scalar @{$This->{Atoms}}; 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 # Set bond order... 218 # 219 # Possible BondOrder are: 1 = Single, 1.5 = Atomatic, 2 = Double, 3 = Triple, 4 = Quadruple. 220 # 221 # Possible BondType for different BondOrders are: 222 # 223 # 1 : Single, SingleWedge (Up), SingleHash (Down), SingleWavy, Dative 224 # 2 : Double, DoubleCross (Cis/Trans) 225 # 3 : Triple 226 # 4 : Quadruple 227 # 1.5 : Aromatic (Single/Double), Tautomeric(Single/Double), Resonance (Single/Double) 228 # 229 # Notes: 230 # . BondType property is automatially assiged using default BondType values for 231 # specified BondOrder. 232 # . BondType values can also be explicit set. 233 # . To make bonds aromatic in a ring, explicitly set "Aromatic" property for bond/atoms and make sure 234 # apporpriate BondOrder values are assgined. 235 # . Dative bond types are treated as single bond types with explicit formal charge of + and - on first 236 # and second bond atoms. 237 # 238 sub SetBondOrder { 239 my($This, $BondOrder) = @_; 240 241 if ($BondOrder !~ /^(1|1.5|2|3|4)$/) { 242 croak "Error: ${ClassName}->SetBondOrder: BondOrder value $BondOrder is not valid. Supported values: 1, 1.5, 2, 3, 4.."; 243 } 244 245 # Set bond order and type... 246 my($BondType); 247 248 BONDORDER: { 249 if ($BondOrder == 1) {$BondType = 'Single'; last BONDORDER; } 250 if ($BondOrder == 1.5) {$BondType = 'Aromatic'; last BONDORDER; } 251 if ($BondOrder == 2) {$BondType = 'Double'; last BONDORDER; } 252 if ($BondOrder == 3) {$BondType = 'Triple'; last BONDORDER; } 253 if ($BondOrder == 4) {$BondType = 'Quadruple'; last BONDORDER; } 254 $BondType = ''; 255 $BondOrder = ''; 256 } 257 $This->{BondType} = $BondType; 258 $This->{BondOrder} = $BondOrder; 259 260 return $This; 261 262 } 263 264 # Set bond type for a specific bond... 265 # 266 sub SetBondType { 267 my($This, $BondType) = @_; 268 269 if ($BondType !~ /^(Single|SingleWedge|SingleUp|SingleHash|SingleDown|SingleWavy|Dative|Double|DoubleCross|Aromatic|Tautomeric|Triple|Quadruple)$/i) { 270 croak "Error: ${ClassName}->SetBondType: BondType value $BondType is not valid. Supported values: Single, SingleWedge, SingleUp, SingleHash, SingleDown, SingleWavy, Dative, Double, DoubleCross, Aromatic, Tautomeric, Triple, Quadruple..."; 271 } 272 273 # Make sure its a valid BondType value for BondOrder... 274 my($BondOrder, $ValidBondType); 275 276 $ValidBondType = 0; 277 $BondOrder = $This->{BondOrder}; 278 if (!$BondOrder) { 279 croak "Error: ${ClassName}->SetBondType: BondOrder is empty: It must be set before BondOrder..."; 280 } 281 282 BONDORDER: { 283 if ($BondOrder == 1 && $BondType =~ /^(Single|SingleWedge|SingleUp|SingleHash|SingleDown|SingleWavy|Dative|Aromatic|Tautomeric)$/i) {$ValidBondType = 1; last BONDORDER; } 284 if ($BondOrder == 1.5 && $BondType =~ /^(Aromatic|Tautomeric)$/i) {$ValidBondType = 1; last BONDORDER; } 285 if ($BondOrder == 2 && $BondType =~ /^(Double|DoubleCross|Aromatic|Tautomeric)$/i ) {$ValidBondType = 1; last BONDORDER; } 286 if ($BondOrder == 3 && $BondType =~ /^(Triple)$/i) {$ValidBondType = 1; last BONDORDER; } 287 if ($BondOrder == 4 && $BondType =~ /^(Quadruple)$/i) {$ValidBondType = 1; last BONDORDER; } 288 $ValidBondType = 0; 289 } 290 291 if (!$ValidBondType) { 292 croak "Error: ${ClassName}->SetBondType: BondType value, $BondType, is not valid for BondOrder $BondOrder..."; 293 } 294 295 $This->{BondType} = $BondType; 296 297 # Set explicit formal charge for atoms involved in Dative bonds... 298 if ($BondType =~ /^Dative$/i) { 299 my($Atom1, $Atom2) = $This->GetAtoms(); 300 $Atom1->SetFormalCharge('1'); 301 $Atom2->SetFormalCharge('-1'); 302 } 303 304 return $This; 305 } 306 307 # Set bond stereochemistry... 308 # 309 # Supported values are: 310 # 311 # Z, cis: Highest ranking group using CIP priority scheme on the same side of double bond 312 # E, trans: Highest ranking group using CIP priority scheme on the same side of double bond 313 # 314 sub SetStereochemistry { 315 my($This, $Stereochemistry) = @_; 316 317 if ($Stereochemistry !~ /^(Z|cis|E|trans)$/i) { 318 croak "Error: ${ClassName}->SetStereochemistry: Stereochemistry value $Stereochemistry is not valid. Supported values: Z, cis, E, trans.."; 319 } 320 my($BondOrder); 321 $BondOrder = $This->{BondOrder}; 322 323 if ($BondOrder != 2) { 324 croak "Error: ${ClassName}->SetStereochemistry: Stereochemistry value, $Stereochemistry, can't be assigned to bond with BondOrder value of $BondOrder: It's only valid for double bonds ..."; 325 } 326 327 $This->SetProperty('Stereochemistry', $Stereochemistry); 328 329 return $This; 330 } 331 332 # Is it a single bond? 333 sub IsSingle { 334 my($This) = @_; 335 336 return ($This->{BondOrder} == 1) ? 1 : 0; 337 } 338 339 # Is it a double bond? 340 sub IsDouble { 341 my($This) = @_; 342 343 return ($This->{BondOrder} == 2) ? 1 : 0; 344 } 345 346 # Is it a triple bond? 347 sub IsTriple { 348 my($This) = @_; 349 350 return ($This->{BondOrder} == 3) ? 1 : 0; 351 } 352 353 # Is aromatic property set for the bond? 354 sub IsAromatic { 355 my($This) = @_; 356 my($Aromatic); 357 358 $Aromatic = $This->GetAromatic(); 359 360 return (defined($Aromatic) && $Aromatic) ? 1 : 0; 361 } 362 363 # Delete bond... 364 sub DeleteBond { 365 my($This) = @_; 366 367 # Is this atom in a molecule? 368 if (!$This->HasProperty('Molecule')) { 369 # Nothing to do... 370 return $This; 371 } 372 my($Molecule); 373 $Molecule = $This->GetProperty('Molecule'); 374 $Molecule->DeleteBond($This); 375 376 return $This; 377 } 378 379 # Copy bond and all its associated data... 380 sub Copy { 381 my($This) = @_; 382 my($Bond); 383 384 $Bond = Storable::dclone($This); 385 386 return $Bond; 387 } 388 389 # Is bond in a ring? 390 # 391 sub IsInRing { 392 my($This) = @_; 393 394 # Is this bond in a molecule? 395 if (!$This->HasProperty('Molecule')) { 396 return undef; 397 } 398 my($Molecule); 399 $Molecule = $This->GetProperty('Molecule'); 400 401 return $Molecule->_IsBondInRing($This); 402 } 403 404 # Is bond not in a ring? 405 # 406 sub IsNotInRing { 407 my($This) = @_; 408 409 # Is this bond in a molecule? 410 if (!$This->HasProperty('Molecule')) { 411 return undef; 412 } 413 my($Molecule); 414 $Molecule = $This->GetProperty('Molecule'); 415 416 return $Molecule->_IsBondNotInRing($This); 417 } 418 419 # Is bond only in one ring? 420 # 421 sub IsOnlyInOneRing { 422 my($This) = @_; 423 424 # Is this bond in a molecule? 425 if (!$This->HasProperty('Molecule')) { 426 return undef; 427 } 428 my($Molecule); 429 $Molecule = $This->GetProperty('Molecule'); 430 431 return $Molecule->_IsBondInOnlyOneRing($This); 432 } 433 434 # Is bond in a ring of specific size? 435 # 436 sub IsInRingOfSize { 437 my($This, $RingSize) = @_; 438 439 # Is this bond in a molecule? 440 if (!$This->HasProperty('Molecule')) { 441 return undef; 442 } 443 my($Molecule); 444 $Molecule = $This->GetProperty('Molecule'); 445 446 return $Molecule->_IsBondInRingOfSize($This, $RingSize); 447 } 448 449 # Get size of smallest ring containing the bond... 450 # 451 sub GetSizeOfSmallestRing { 452 my($This) = @_; 453 454 # Is this bond in a molecule? 455 if (!$This->HasProperty('Molecule')) { 456 return undef; 457 } 458 my($Molecule); 459 $Molecule = $This->GetProperty('Molecule'); 460 461 return $Molecule->_GetSizeOfSmallestBondRing($This); 462 } 463 464 # Get size of largest ring containing the bond... 465 # 466 sub GetSizeOfLargestRing { 467 my($This) = @_; 468 469 # Is this bond in a molecule? 470 if (!$This->HasProperty('Molecule')) { 471 return undef; 472 } 473 my($Molecule); 474 $Molecule = $This->GetProperty('Molecule'); 475 476 return $Molecule->_GetSizeOfLargestBondRing($This); 477 } 478 479 # Get number of rings containing the bond... 480 # 481 sub GetNumOfRings { 482 my($This) = @_; 483 484 # Is this bond in a molecule? 485 if (!$This->HasProperty('Molecule')) { 486 return undef; 487 } 488 my($Molecule); 489 $Molecule = $This->GetProperty('Molecule'); 490 491 return $Molecule->_GetNumOfBondRings($This); 492 } 493 494 # Get number of rings with odd size containing the bond... 495 # 496 sub GetNumOfRingsWithOddSize { 497 my($This) = @_; 498 499 # Is this bond in a molecule? 500 if (!$This->HasProperty('Molecule')) { 501 return undef; 502 } 503 my($Molecule); 504 $Molecule = $This->GetProperty('Molecule'); 505 506 return $Molecule->_GetNumOfBondRingsWithOddSize($This); 507 } 508 509 # Get number of rings with even size containing the bond... 510 # 511 sub GetNumOfRingsWithEvenSize { 512 my($This) = @_; 513 514 # Is this bond in a molecule? 515 if (!$This->HasProperty('Molecule')) { 516 return undef; 517 } 518 my($Molecule); 519 $Molecule = $This->GetProperty('Molecule'); 520 521 return $Molecule->_GetNumOfBondRingsWithEvenSize($This); 522 } 523 524 # Get number of rings with specified size containing the bond... 525 # 526 sub GetNumOfRingsWithSize { 527 my($This, $RingSize) = @_; 528 529 # Is this bond in a molecule? 530 if (!$This->HasProperty('Molecule')) { 531 return undef; 532 } 533 my($Molecule); 534 $Molecule = $This->GetProperty('Molecule'); 535 536 return $Molecule->_GetNumOfBondRingsWithSize($This, $RingSize); 537 } 538 539 # Get number of rings with size less than specified containing the bond... 540 # 541 sub GetNumOfRingsWithSizeLessThan { 542 my($This, $RingSize) = @_; 543 544 # Is this bond in a molecule? 545 if (!$This->HasProperty('Molecule')) { 546 return undef; 547 } 548 my($Molecule); 549 $Molecule = $This->GetProperty('Molecule'); 550 551 return $Molecule->_GetNumOfBondRingsWithSizeLessThan($This, $RingSize); 552 } 553 554 # Get number of rings with size greater than specified size containing the bond... 555 # 556 sub GetNumOfRingsWithSizeGreaterThan { 557 my($This, $RingSize) = @_; 558 559 # Is this bond in a molecule? 560 if (!$This->HasProperty('Molecule')) { 561 return undef; 562 } 563 my($Molecule); 564 $Molecule = $This->GetProperty('Molecule'); 565 566 return $Molecule->_GetNumOfBondRingsWithSizeGreaterThan($This, $RingSize); 567 } 568 569 # Get all rings as an array of references to arrays containing ring atoms... 570 # 571 sub GetRings { 572 my($This) = @_; 573 574 # Is this bond in a molecule? 575 if (!$This->HasProperty('Molecule')) { 576 return undef; 577 } 578 my($Molecule); 579 $Molecule = $This->GetProperty('Molecule'); 580 581 return $Molecule->_GetBondRings($This); 582 } 583 584 # Get smallest ring as an array containing ring atoms... 585 # 586 sub GetSmallestRing { 587 my($This) = @_; 588 589 # Is this bond in a molecule? 590 if (!$This->HasProperty('Molecule')) { 591 return undef; 592 } 593 my($Molecule); 594 $Molecule = $This->GetProperty('Molecule'); 595 596 return $Molecule->_GetSmallestBondRing($This); 597 } 598 599 # Get largest ring as an array containing ring atoms... 600 # 601 sub GetLargestRing { 602 my($This) = @_; 603 604 # Is this bond in a molecule? 605 if (!$This->HasProperty('Molecule')) { 606 return undef; 607 } 608 my($Molecule); 609 $Molecule = $This->GetProperty('Molecule'); 610 611 return $Molecule->_GetLargestBondRing($This); 612 } 613 614 # Get odd size rings an array of references to arrays containing ring atoms... 615 # 616 sub GetRingsWithOddSize { 617 my($This) = @_; 618 619 # Is this bond in a molecule? 620 if (!$This->HasProperty('Molecule')) { 621 return undef; 622 } 623 my($Molecule); 624 $Molecule = $This->GetProperty('Molecule'); 625 626 return $Molecule->_GetBondRingsWithOddSize($This); 627 } 628 629 # Get even size rings an array of references to arrays containing ring atoms... 630 # 631 sub GetRingsWithEvenSize { 632 my($This) = @_; 633 634 # Is this bond in a molecule? 635 if (!$This->HasProperty('Molecule')) { 636 return undef; 637 } 638 my($Molecule); 639 $Molecule = $This->GetProperty('Molecule'); 640 641 return $Molecule->_GetBondRingsWithEvenSize($This); 642 } 643 644 # Get rings with specified size an array of references to arrays containing ring atoms... 645 # 646 sub GetRingsWithSize { 647 my($This, $RingSize) = @_; 648 649 # Is this bond in a molecule? 650 if (!$This->HasProperty('Molecule')) { 651 return undef; 652 } 653 my($Molecule); 654 $Molecule = $This->GetProperty('Molecule'); 655 656 return $Molecule->_GetBondRingsWithSize($This, $RingSize); 657 } 658 659 # Get rings with size less than specfied size as an array of references to arrays containing ring atoms... 660 # 661 sub GetRingsWithSizeLessThan { 662 my($This, $RingSize) = @_; 663 664 # Is this bond in a molecule? 665 if (!$This->HasProperty('Molecule')) { 666 return undef; 667 } 668 my($Molecule); 669 $Molecule = $This->GetProperty('Molecule'); 670 671 return $Molecule->_GetBondRingsWithSizeLessThan($This, $RingSize); 672 } 673 674 # Get rings with size greater than specfied size as an array of references to arrays containing ring atoms... 675 # 676 sub GetRingsWithSizeGreaterThan { 677 my($This, $RingSize) = @_; 678 679 # Is this bond in a molecule? 680 if (!$This->HasProperty('Molecule')) { 681 return undef; 682 } 683 my($Molecule); 684 $Molecule = $This->GetProperty('Molecule'); 685 686 return $Molecule->_GetBondRingsWithSizeGreaterThan($This, $RingSize); 687 } 688 689 # Get next object ID... 690 sub _GetNewObjectID { 691 $ObjectID++; 692 return $ObjectID; 693 } 694 695 # Return a string containing bond and other properties... 696 sub StringifyBond { 697 my($This) = @_; 698 my($BondString, $ID, $BondOrder, $BondType, $Stereochemistry, $AtomsString, $RingBond, $NumOfRings, $Atom1, $Atom2); 699 700 $ID = $This->GetID(); 701 $BondOrder = $This->GetBondOrder(); 702 if (!defined $BondOrder) { 703 $BondOrder = "undefined"; 704 } 705 $BondType = $This->GetBondType(); 706 if (!defined $BondOrder) { 707 $BondType = "undefined"; 708 } 709 if (defined($BondOrder) && $BondOrder == 2) { 710 $Stereochemistry = $This->GetStereochemistry(); 711 if (!defined $Stereochemistry) { 712 $Stereochemistry = "undefined"; 713 } 714 } 715 $RingBond = $This->IsInRing(); 716 if (defined $RingBond) { 717 $RingBond = $RingBond ? 'Yes' : 'No'; 718 $NumOfRings = $This->GetNumOfRings(); 719 } 720 else { 721 $RingBond = 'undefined'; 722 $NumOfRings = 'undefined'; 723 } 724 725 ($Atom1, $Atom2) = $This->GetAtoms(); 726 $AtomsString = "Atoms: undefined"; 727 if (defined($Atom1) && defined($Atom2)) { 728 my($Atom, $AtomID, $AtomCount, $AtomName, $AtomSymbol, $AtomicNumber, @BondAtoms); 729 @BondAtoms = (); 730 push @BondAtoms, ($Atom1, $Atom2); 731 $AtomCount = 0; 732 $AtomsString = ""; 733 for $Atom (@BondAtoms) { 734 $AtomCount++; 735 $AtomID = $Atom->GetID(); 736 $AtomName = $Atom->GetName(); 737 $AtomSymbol = $Atom->GetAtomSymbol(); 738 $AtomicNumber = $Atom->GetAtomicNumber(); 739 if ($AtomCount == 1) { 740 $AtomsString .= "FirstAtom:"; 741 } 742 else { 743 $AtomsString .= "; SecondAtom:"; 744 } 745 $AtomsString .= " [ ID: $AtomID; Name: \"$AtomName\"; AtomSymbol: \"$AtomSymbol\"; AtomicNumber: $AtomicNumber ]"; 746 } 747 } 748 $BondString = "Bond: ID: $ID; BondOrder: $BondOrder; BondType: $BondType; RingBond: $RingBond; NumOfBondRings: $NumOfRings"; 749 if (defined($BondOrder) && $BondOrder == 2) { 750 $BondString .= " Stereochemistry: $Stereochemistry;"; 751 } 752 $BondString .= " $AtomsString"; 753 754 return $BondString; 755 } 756