1 /* Copyright (C) 1997-2007 Christoph Steinbeck 2 * 3 * Contact: cdk-devel@lists.sourceforge.net 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public License 7 * as published by the Free Software Foundation; either version 2.1 8 * of the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 package org.openscience.cdk.silent; 20 21 import org.openscience.cdk.CDKConstants; 22 import org.openscience.cdk.exception.NoSuchAtomException; 23 import org.openscience.cdk.interfaces.IAtom; 24 import org.openscience.cdk.interfaces.IAtomContainer; 25 import org.openscience.cdk.interfaces.IBond; 26 import org.openscience.cdk.interfaces.IBond.Order; 27 import org.openscience.cdk.interfaces.IChemObject; 28 import org.openscience.cdk.interfaces.IChemObjectChangeEvent; 29 import org.openscience.cdk.interfaces.IChemObjectListener; 30 import org.openscience.cdk.interfaces.IElectronContainer; 31 import org.openscience.cdk.interfaces.ILonePair; 32 import org.openscience.cdk.interfaces.ISingleElectron; 33 import org.openscience.cdk.interfaces.IStereoElement; 34 import org.openscience.cdk.sgroup.Sgroup; 35 import org.openscience.cdk.tools.manipulator.SgroupManipulator; 36 37 import java.io.Serializable; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.Collection; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.Iterator; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.NoSuchElementException; 48 import java.util.Set; 49 50 /** 51 * Base class for all chemical objects that maintain a list of Atoms and 52 * ElectronContainers. <p> 53 * <p> 54 * Looping over all Bonds in the AtomContainer is typically done like: <pre> 55 * Iterator iter = atomContainer.bonds(); 56 * while (iter.hasNext()) { 57 * IBond aBond = (IBond) iter.next(); 58 * } 59 * </pre> 60 * 61 * @author steinbeck 62 * @cdk.module silent 63 * @cdk.githash 64 * @cdk.created 2000-10-02 65 */ 66 public class AtomContainer extends ChemObject implements IAtomContainer, IChemObjectListener, Serializable, Cloneable { 67 68 private static final int DEFAULT_CAPACITY = 20; 69 70 /** 71 * Determines if a de-serialized object is compatible with this class. 72 * <p> 73 * This value must only be changed if and only if the new version 74 * of this class is incompatible with the old version. See Sun docs 75 * for <a href=http://java.sun.com/products/jdk/1.1/docs/guide 76 * /serialization/spec/version.doc.html>details</a>. 77 */ 78 private static final long serialVersionUID = 5678100348445919254L; 79 80 /** 81 * Number of atoms contained by this object. 82 */ 83 protected int atomCount; 84 85 /** 86 * Number of bonds contained by this object. 87 */ 88 protected int bondCount; 89 90 /** 91 * Number of lone pairs contained by this object. 92 */ 93 protected int lonePairCount; 94 95 /** 96 * Number of single electrons contained by this object. 97 */ 98 protected int singleElectronCount; 99 100 /** 101 * Amount by which the bond and atom arrays grow when elements are added and 102 * the arrays are not large enough for that. 103 */ 104 protected int growArraySize = 10; 105 106 /** 107 * Internal array of atoms. 108 */ 109 protected IAtom[] atoms; 110 111 /** 112 * Internal array of bonds. 113 */ 114 protected IBond[] bonds; 115 116 /** 117 * Internal array of lone pairs. 118 */ 119 protected ILonePair[] lonePairs; 120 121 /** 122 * Internal array of single electrons. 123 */ 124 protected ISingleElectron[] singleElectrons; 125 126 /** 127 * Internal list of atom parities. 128 */ 129 protected Set<IStereoElement> stereoElements; 130 131 /** 132 * Constructs an empty AtomContainer. 133 */ AtomContainer()134 public AtomContainer() { 135 this(0, 0, 0, 0); 136 } 137 138 /** 139 * Constructs an AtomContainer with a copy of the atoms and electronContainers 140 * of another AtomContainer (A shallow copy, i.e., with the same objects as in 141 * the original AtomContainer). 142 * 143 * @param container An AtomContainer to copy the atoms and electronContainers from 144 */ AtomContainer(IAtomContainer container)145 public AtomContainer(IAtomContainer container) { 146 this.atomCount = container.getAtomCount(); 147 this.bondCount = container.getBondCount(); 148 this.lonePairCount = container.getLonePairCount(); 149 this.singleElectronCount = container.getSingleElectronCount(); 150 this.atoms = new IAtom[this.atomCount]; 151 this.bonds = new IBond[this.bondCount]; 152 this.lonePairs = new ILonePair[this.lonePairCount]; 153 this.singleElectrons = new ISingleElectron[this.singleElectronCount]; 154 155 stereoElements = new HashSet<IStereoElement>(atomCount / 2); 156 157 for (IStereoElement element : container.stereoElements()) { 158 addStereoElement(element); 159 } 160 161 for (int f = 0; f < container.getAtomCount(); f++) { 162 atoms[f] = container.getAtom(f); 163 } 164 for (int f = 0; f < this.bondCount; f++) { 165 bonds[f] = container.getBond(f); 166 } 167 for (int f = 0; f < this.lonePairCount; f++) { 168 lonePairs[f] = container.getLonePair(f); 169 } 170 for (int f = 0; f < this.singleElectronCount; f++) { 171 singleElectrons[f] = container.getSingleElectron(f); 172 } 173 } 174 175 /** 176 * Constructs an empty AtomContainer that will contain a certain number of 177 * atoms and electronContainers. It will set the starting array lengths to the 178 * defined values, but will not create any Atom or ElectronContainer's. 179 * 180 * @param atomCount Number of atoms to be in this container 181 * @param bondCount Number of bonds to be in this container 182 * @param lpCount Number of lone pairs to be in this container 183 * @param seCount Number of single electrons to be in this container 184 */ AtomContainer(int atomCount, int bondCount, int lpCount, int seCount)185 public AtomContainer(int atomCount, int bondCount, int lpCount, 186 int seCount) { 187 this.atomCount = 0; 188 this.bondCount = 0; 189 this.lonePairCount = 0; 190 this.singleElectronCount = 0; 191 atoms = new IAtom[atomCount]; 192 bonds = new IBond[bondCount]; 193 lonePairs = new ILonePair[lpCount]; 194 singleElectrons = new ISingleElectron[seCount]; 195 stereoElements = new HashSet<IStereoElement>(atomCount / 2); 196 } 197 198 /** 199 * {@inheritDoc} 200 */ 201 @Override addStereoElement(IStereoElement element)202 public void addStereoElement(IStereoElement element) { 203 stereoElements.add(element); 204 } 205 206 /** 207 * {@inheritDoc} 208 */ 209 @Override setStereoElements(List<IStereoElement> elements)210 public void setStereoElements(List<IStereoElement> elements) { 211 this.stereoElements = new HashSet<IStereoElement>(); 212 this.stereoElements.addAll(elements); 213 } 214 215 /** 216 * {@inheritDoc} 217 */ 218 @Override stereoElements()219 public Iterable<IStereoElement> stereoElements() { 220 return Collections.unmodifiableSet(stereoElements); 221 } 222 223 /** 224 * {@inheritDoc} 225 */ 226 @Override setAtoms(IAtom[] newAtoms)227 public void setAtoms(IAtom[] newAtoms) { 228 ensureAtomCapacity(newAtoms.length); 229 System.arraycopy(newAtoms, 0, this.atoms, 0, newAtoms.length); 230 if (newAtoms.length < this.atoms.length) 231 Arrays.fill(atoms, newAtoms.length, this.atoms.length, null); 232 this.atomCount = newAtoms.length; 233 } 234 235 /** 236 * {@inheritDoc} 237 */ 238 @Override setBonds(IBond[] newBonds)239 public void setBonds(IBond[] newBonds) { 240 ensureBondCapacity(newBonds.length); 241 System.arraycopy(newBonds, 0, this.bonds, 0, newBonds.length); 242 if (newBonds.length < this.bonds.length) 243 Arrays.fill(bonds, newBonds.length, this.bonds.length, null); 244 this.bondCount = newBonds.length; 245 } 246 247 /** 248 * {@inheritDoc} 249 */ 250 @Override setAtom(int idx, IAtom atom)251 public void setAtom(int idx, IAtom atom) { 252 if (idx >= atomCount) 253 throw new IndexOutOfBoundsException("No atom at index: " + idx); 254 int aidx = indexOf(atom); 255 if (aidx >= 0) 256 throw new IllegalArgumentException("Atom already in container at index: " + idx); 257 final IAtom oldAtom = atoms[idx]; 258 atoms[idx] = atom; 259 260 // update electron containers 261 for (IBond bond : bonds()) { 262 for (int i = 0; i < bond.getAtomCount(); i++) { 263 if (oldAtom.equals(bond.getAtom(i))) { 264 bond.setAtom(atom, i); 265 } 266 } 267 } 268 for (ISingleElectron ec : singleElectrons()) { 269 if (oldAtom.equals(ec.getAtom())) 270 ec.setAtom(atom); 271 } 272 for (ILonePair lp : lonePairs()) { 273 if (oldAtom.equals(lp.getAtom())) 274 lp.setAtom(atom); 275 } 276 277 // update stereo 278 List<IStereoElement> oldStereo = null; 279 List<IStereoElement> newStereo = null; 280 for (IStereoElement se : stereoElements()) { 281 if (se.contains(oldAtom)) { 282 if (oldStereo == null) { 283 oldStereo = new ArrayList<>(); 284 newStereo = new ArrayList<>(); 285 } 286 oldStereo.add(se); 287 Map<IAtom, IAtom> amap = Collections.singletonMap(oldAtom, atom); 288 Map<IBond, IBond> bmap = Collections.emptyMap(); 289 newStereo.add(se.map(amap, bmap)); 290 } 291 } 292 if (oldStereo != null) { 293 stereoElements.removeAll(oldStereo); 294 stereoElements.addAll(newStereo); 295 } 296 } 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override getAtom(int idx)302 public IAtom getAtom(int idx) { 303 if (idx < 0 || idx >= atomCount) 304 throw new IndexOutOfBoundsException("Atom index out of bounds: 0 <= " + idx + " < " + atomCount); 305 return atoms[idx]; 306 } 307 308 /** 309 * {@inheritDoc} 310 */ 311 @Override getBond(int idx)312 public IBond getBond(int idx) { 313 if (idx < 0 || idx >= bondCount) 314 throw new IndexOutOfBoundsException("Bond index out of bounds: 0 <= " + idx + " < " + bondCount); 315 return bonds[idx]; 316 } 317 318 /** 319 * {@inheritDoc} 320 */ 321 @Override getLonePair(int idx)322 public ILonePair getLonePair(int idx) { 323 if (idx < 0 || idx >= lonePairCount) 324 throw new IndexOutOfBoundsException("Lone Pair index out of bounds: 0 <= " + idx + " < " + lonePairCount); 325 return lonePairs[idx]; 326 } 327 328 /** 329 * {@inheritDoc} 330 */ 331 @Override getSingleElectron(int idx)332 public ISingleElectron getSingleElectron(int idx) { 333 if (idx < 0 || idx >= singleElectronCount) 334 throw new IndexOutOfBoundsException("Single Electrong index out of bounds: 0 <= " + idx + " < " + singleElectronCount); 335 return singleElectrons[idx]; 336 } 337 338 /** 339 * {@inheritDoc} 340 */ 341 @Override atoms()342 public Iterable<IAtom> atoms() { 343 return new Iterable<IAtom>() { 344 345 @Override 346 public Iterator<IAtom> iterator() { 347 return new AtomIterator(); 348 } 349 }; 350 } 351 352 /** 353 * {@inheritDoc} 354 */ 355 @Override 356 public Iterable<IBond> bonds() { 357 return new Iterable<IBond>() { 358 359 @Override 360 public Iterator<IBond> iterator() { 361 return new BondIterator(); 362 } 363 }; 364 } 365 366 /** 367 * {@inheritDoc} 368 */ 369 @Override 370 public Iterable<ILonePair> lonePairs() { 371 return new Iterable<ILonePair>() { 372 373 @Override 374 public Iterator<ILonePair> iterator() { 375 return new LonePairIterator(); 376 } 377 }; 378 } 379 380 /** 381 * {@inheritDoc} 382 */ 383 @Override 384 public Iterable<ISingleElectron> singleElectrons() { 385 return new Iterable<ISingleElectron>() { 386 387 @Override 388 public Iterator<ISingleElectron> iterator() { 389 return new SingleElectronIterator(); 390 } 391 }; 392 } 393 394 /** 395 * {@inheritDoc} 396 */ 397 @Override 398 public Iterable<IElectronContainer> electronContainers() { 399 return new Iterable<IElectronContainer>() { 400 401 @Override 402 public Iterator<IElectronContainer> iterator() { 403 return new ElectronContainerIterator(); 404 } 405 }; 406 } 407 408 /** 409 * {@inheritDoc} 410 */ 411 @Override 412 public IAtom getFirstAtom() { 413 return atoms[0]; 414 } 415 416 /** 417 * {@inheritDoc} 418 */ 419 @Override 420 public IAtom getLastAtom() { 421 return getAtomCount() > 0 ? (IAtom) atoms[getAtomCount() - 1] : null; 422 } 423 424 /** 425 * {@inheritDoc} 426 */ 427 @Override 428 public int getAtomNumber(IAtom atom) { 429 return indexOf(atom); 430 } 431 432 /** 433 * {@inheritDoc} 434 */ 435 @Override 436 public int getBondNumber(IAtom atom1, IAtom atom2) { 437 return indexOf(getBond(atom1, atom2)); 438 } 439 440 /** 441 * {@inheritDoc} 442 */ 443 @Override 444 public int getBondNumber(IBond bond) { 445 return indexOf(bond); 446 } 447 448 /** 449 * {@inheritDoc} 450 */ 451 @Override 452 public int getLonePairNumber(ILonePair lonePair) { 453 return indexOf(lonePair); 454 } 455 456 /** 457 * {@inheritDoc} 458 */ 459 @Override 460 public int getSingleElectronNumber(ISingleElectron singleElectron) { 461 return indexOf(singleElectron); 462 } 463 464 /** 465 * {@inheritDoc} 466 */ 467 @Override 468 public int indexOf(IAtom atom) { 469 for (int i = 0; i < atomCount; i++) { 470 if (atoms[i].equals(atom)) return i; 471 } 472 return -1; 473 } 474 475 /** 476 * {@inheritDoc} 477 */ 478 @Override 479 public int indexOf(IBond bond) { 480 for (int i = 0; i < bondCount; i++) { 481 if (bonds[i].equals(bond)) return i; 482 } 483 return -1; 484 } 485 486 /** 487 * {@inheritDoc} 488 */ 489 @Override 490 public int indexOf(ISingleElectron electron) { 491 for (int i = 0; i < singleElectronCount; i++) { 492 if (singleElectrons[i] == electron) return i; 493 } 494 return -1; 495 } 496 497 /** 498 * {@inheritDoc} 499 */ 500 @Override 501 public int indexOf(ILonePair pair) { 502 for (int i = 0; i < lonePairCount; i++) { 503 if (lonePairs[i] == pair) return i; 504 } 505 return -1; 506 } 507 508 /** 509 * {@inheritDoc} 510 */ 511 @Override 512 public IElectronContainer getElectronContainer(int number) { 513 if (number < this.bondCount) return bonds[number]; 514 number -= this.bondCount; 515 if (number < this.lonePairCount) return lonePairs[number]; 516 number -= this.lonePairCount; 517 if (number < this.singleElectronCount) return singleElectrons[number]; 518 return null; 519 } 520 521 /** 522 * {@inheritDoc} 523 */ 524 @Override 525 public IBond getBond(IAtom atom1, IAtom atom2) { 526 for (int i = 0; i < getBondCount(); i++) { 527 if (bonds[i].contains(atom1) && bonds[i].getOther(atom1).equals(atom2)) { 528 return bonds[i]; 529 } 530 } 531 return null; 532 } 533 534 /** 535 * {@inheritDoc} 536 */ 537 @Override 538 public int getAtomCount() { 539 return this.atomCount; 540 } 541 542 /** 543 * {@inheritDoc} 544 */ 545 @Override 546 public int getBondCount() { 547 return this.bondCount; 548 } 549 550 /** 551 * {@inheritDoc} 552 */ 553 @Override 554 public int getLonePairCount() { 555 return this.lonePairCount; 556 } 557 558 /** 559 * {@inheritDoc} 560 */ 561 @Override 562 public int getSingleElectronCount() { 563 return this.singleElectronCount; 564 } 565 566 /** 567 * {@inheritDoc} 568 */ 569 @Override 570 public int getElectronContainerCount() { 571 return this.bondCount + this.lonePairCount + this.singleElectronCount; 572 } 573 574 /** 575 * {@inheritDoc} 576 */ 577 @Override 578 public List<IAtom> getConnectedAtomsList(IAtom atom) { 579 List<IAtom> atomsList = new ArrayList<>(4); 580 for (int i = 0; i < bondCount; i++) { 581 if (bonds[i].contains(atom)) 582 atomsList.add(bonds[i].getOther(atom)); 583 } 584 if (atomsList.isEmpty() && !contains(atom)) 585 throw new NoSuchAtomException("Atom does not belong to the container!"); 586 return atomsList; 587 } 588 589 /** 590 * {@inheritDoc} 591 */ 592 @Override 593 public List<IBond> getConnectedBondsList(IAtom atom) { 594 List<IBond> bondsList = new ArrayList<>(4); 595 for (int i = 0; i < bondCount; i++) { 596 if (bonds[i].contains(atom)) 597 bondsList.add(bonds[i]); 598 } 599 if (bondsList.isEmpty() && !contains(atom)) 600 throw new NoSuchAtomException("Atom does not belong to the container!"); 601 return bondsList; 602 } 603 604 /** 605 * {@inheritDoc} 606 */ 607 @Override 608 public List<ILonePair> getConnectedLonePairsList(IAtom atom) { 609 List<ILonePair> lps = new ArrayList<>(2); 610 for (int i = 0; i < lonePairCount; i++) { 611 if (lonePairs[i].contains(atom)) 612 lps.add(lonePairs[i]); 613 } 614 if (lps.isEmpty() && !contains(atom)) 615 throw new NoSuchAtomException("Atom does not belong to the container!"); 616 return lps; 617 } 618 619 /** 620 * {@inheritDoc} 621 */ 622 @Override 623 public List<ISingleElectron> getConnectedSingleElectronsList(IAtom atom) { 624 List<ISingleElectron> ses = new ArrayList<>(2); 625 for (int i = 0; i < singleElectronCount; i++) { 626 if (singleElectrons[i].contains(atom)) 627 ses.add(singleElectrons[i]); 628 } 629 if (ses.isEmpty() && !contains(atom)) 630 throw new NoSuchAtomException("Atom does not belong to the container!"); 631 return ses; 632 } 633 634 /** 635 * {@inheritDoc} 636 */ 637 @Override 638 public List<IElectronContainer> getConnectedElectronContainersList( 639 IAtom atom) { 640 List<IElectronContainer> ecs = new ArrayList<>(4); 641 for (int i = 0; i < bondCount; i++) { 642 if (bonds[i].contains(atom)) ecs.add(bonds[i]); 643 } 644 for (int i = 0; i < lonePairCount; i++) { 645 if (lonePairs[i].contains(atom)) ecs.add(lonePairs[i]); 646 } 647 for (int i = 0; i < singleElectronCount; i++) { 648 if (singleElectrons[i].contains(atom)) ecs.add(singleElectrons[i]); 649 } 650 if (ecs.isEmpty() && !contains(atom)) 651 throw new NoSuchElementException("Atom does not belong to the container!"); 652 return ecs; 653 } 654 655 /** 656 * {@inheritDoc} 657 */ 658 @Override 659 public int getConnectedBondsCount(IAtom atom) { 660 int count = 0; 661 for (int i = 0; i < bondCount; i++) { 662 if (bonds[i].contains(atom)) ++count; 663 } 664 if (count == 0 && !contains(atom)) 665 throw new NoSuchAtomException("Atom does not belong to the container!"); 666 return count; 667 } 668 669 /** 670 * {@inheritDoc} 671 */ 672 @Override 673 public int getConnectedAtomsCount(IAtom atom) { 674 return getConnectedBondsCount(atom); 675 } 676 677 /** 678 * {@inheritDoc} 679 */ 680 @Override 681 public int getConnectedBondsCount(int idx) { 682 final IAtom atom = getAtom(idx); 683 int count = 0; 684 for (int i = 0; i < bondCount; i++) { 685 if (bonds[i].contains(atom)) ++count; 686 } 687 // no need to check the contains(atom) as getAtom does this already 688 return count; 689 } 690 691 /** 692 * {@inheritDoc} 693 */ 694 @Override 695 public int getConnectedLonePairsCount(IAtom atom) { 696 int count = 0; 697 for (int i = 0; i < lonePairCount; i++) { 698 if (lonePairs[i].contains(atom)) 699 ++count; 700 } 701 if (count == 0 && !contains(atom)) 702 throw new NoSuchAtomException("Atom does not belong to the container!"); 703 return count; 704 } 705 706 /** 707 * {@inheritDoc} 708 */ 709 @Override 710 public int getConnectedSingleElectronsCount(IAtom atom) { 711 int count = 0; 712 for (int i = 0; i < singleElectronCount; i++) { 713 if (singleElectrons[i].contains(atom)) ++count; 714 } 715 if (count == 0 && !contains(atom)) 716 throw new NoSuchAtomException("Atom does not belong to the container!"); 717 return count; 718 } 719 720 /** 721 * {@inheritDoc} 722 */ 723 @Override 724 public double getBondOrderSum(IAtom atom) { 725 double count = 0; 726 for (int i = 0; i < bondCount; i++) { 727 if (bonds[i].contains(atom)) { 728 IBond.Order order = bonds[i].getOrder(); 729 if (order != null) { 730 count += order.numeric(); 731 } 732 } 733 } 734 return count; 735 } 736 737 /** 738 * {@inheritDoc} 739 */ 740 @Override 741 public Order getMaximumBondOrder(IAtom atom) { 742 IBond.Order max = null; 743 for (IBond bond : bonds()) { 744 if (!bond.contains(atom)) 745 continue; 746 if (max == null || bond.getOrder().numeric() > max.numeric()) { 747 max = bond.getOrder(); 748 } 749 } 750 if (max == null) { 751 if (!contains(atom)) 752 throw new NoSuchAtomException("Atom does not belong to this container!"); 753 if (atom.getImplicitHydrogenCount() != null && 754 atom.getImplicitHydrogenCount() > 0) 755 max = Order.SINGLE; 756 else 757 max = Order.UNSET; 758 } 759 return max; 760 } 761 762 /** 763 * {@inheritDoc} 764 */ 765 @Override 766 public Order getMinimumBondOrder(IAtom atom) { 767 IBond.Order min = null; 768 for (IBond bond : bonds()) { 769 if (!bond.contains(atom)) 770 continue; 771 if (min == null || bond.getOrder().numeric() < min.numeric()) { 772 min = bond.getOrder(); 773 } 774 } 775 if (min == null) { 776 if (!contains(atom)) 777 throw new NoSuchAtomException("Atom does not belong to this container!"); 778 if (atom.getImplicitHydrogenCount() != null && 779 atom.getImplicitHydrogenCount() > 0) 780 min = Order.SINGLE; 781 else 782 min = Order.UNSET; 783 } 784 return min; 785 } 786 787 /** 788 * {@inheritDoc} 789 */ 790 @Override 791 public void add(IAtomContainer that) { 792 793 atoms = Arrays.copyOf(atoms, atomCount + that.getAtomCount()); 794 bonds = Arrays.copyOf(bonds, bondCount + that.getBondCount()); 795 796 for (IAtom atom : that.atoms()) 797 atom.setFlag(CDKConstants.VISITED, false); 798 for (IBond bond : that.bonds()) 799 bond.setFlag(CDKConstants.VISITED, false); 800 for (IAtom atom : this.atoms()) 801 atom.setFlag(CDKConstants.VISITED, true); 802 for (IBond bond : this.bonds()) 803 bond.setFlag(CDKConstants.VISITED, true); 804 805 for (IAtom atom : that.atoms()) { 806 if (!atom.getFlag(CDKConstants.VISITED)) { 807 atom.setFlag(CDKConstants.VISITED, true); 808 atoms[atomCount++] = atom; 809 } 810 } 811 for (IBond bond : that.bonds()) { 812 if (!bond.getFlag(CDKConstants.VISITED)) { 813 bond.setFlag(CDKConstants.VISITED, true); 814 bonds[bondCount++] = bond; 815 } 816 } 817 for (ILonePair lp : that.lonePairs()) { 818 if (!contains(lp)) { 819 addLonePair(lp); 820 } 821 } 822 for (ISingleElectron se : that.singleElectrons()) { 823 if (!contains(se)) { 824 addSingleElectron(se); 825 } 826 } 827 for (IStereoElement se : that.stereoElements()) 828 stereoElements.add(se); 829 } 830 831 /** 832 * {@inheritDoc} 833 */ 834 @Override 835 public void addAtom(IAtom atom) { 836 if (contains(atom)) { 837 return; 838 } 839 ensureAtomCapacity(atomCount + 1); 840 atoms[atomCount++] = atom; 841 } 842 843 /** 844 * {@inheritDoc} 845 */ 846 @Override 847 public void addBond(IBond bond) { 848 ensureBondCapacity(bondCount + 1); 849 bonds[bondCount++] = bond; 850 } 851 852 /** 853 * {@inheritDoc} 854 */ 855 @Override 856 public void addLonePair(ILonePair lonePair) { 857 ensureLonePairCapacity(lonePairCount + 1); 858 lonePairs[lonePairCount++] = lonePair; 859 } 860 861 /** 862 * {@inheritDoc} 863 */ 864 @Override 865 public void addSingleElectron(ISingleElectron singleElectron) { 866 ensureElectronCapacity(singleElectronCount + 1); 867 singleElectrons[singleElectronCount++] = singleElectron; 868 } 869 870 /** 871 * {@inheritDoc} 872 */ 873 @Override 874 public void addElectronContainer(IElectronContainer electronContainer) { 875 if (electronContainer instanceof IBond) 876 this.addBond((IBond) electronContainer); 877 if (electronContainer instanceof ILonePair) 878 this.addLonePair((ILonePair) electronContainer); 879 if (electronContainer instanceof ISingleElectron) 880 this.addSingleElectron((ISingleElectron) electronContainer); 881 } 882 883 /** 884 * {@inheritDoc} 885 */ 886 @Override 887 public void remove(IAtomContainer atomContainer) { 888 for (int f = 0; f < atomContainer.getAtomCount(); f++) { 889 removeAtomOnly(atomContainer.getAtom(f)); 890 } 891 for (int f = 0; f < atomContainer.getBondCount(); f++) { 892 removeBond(atomContainer.getBond(f)); 893 } 894 for (int f = 0; f < atomContainer.getLonePairCount(); f++) { 895 removeLonePair(atomContainer.getLonePair(f)); 896 } 897 for (int f = 0; f < atomContainer.getSingleElectronCount(); f++) { 898 removeSingleElectron(atomContainer.getSingleElectron(f)); 899 } 900 } 901 902 /** 903 * {@inheritDoc} 904 */ 905 @Override 906 public void removeAtomOnly(int position) { 907 for (int i = position; i < atomCount - 1; i++) { 908 atoms[i] = atoms[i + 1]; 909 } 910 atoms[atomCount - 1] = null; 911 atomCount--; 912 } 913 914 /** 915 * {@inheritDoc} 916 */ 917 @Override 918 public void removeAtomOnly(IAtom atom) { 919 int position = getAtomNumber(atom); 920 if (position != -1) { 921 removeAtomOnly(position); 922 } 923 } 924 925 /** 926 * {@inheritDoc} 927 */ 928 @Override 929 public IBond removeBond(int position) { 930 IBond bond = bonds[position]; 931 for (int i = position; i < bondCount - 1; i++) { 932 bonds[i] = bonds[i + 1]; 933 } 934 bonds[bondCount - 1] = null; 935 bondCount--; 936 return bond; 937 } 938 939 /** 940 * {@inheritDoc} 941 */ 942 @Override 943 public IBond removeBond(IAtom atom1, IAtom atom2) { 944 int pos = indexOf(getBond(atom1, atom2)); 945 IBond bond = null; 946 if (pos != -1) { 947 bond = bonds[pos]; 948 removeBond(pos); 949 } 950 return bond; 951 } 952 953 /** 954 * {@inheritDoc} 955 */ 956 @Override 957 public void removeBond(IBond bond) { 958 int pos = getBondNumber(bond); 959 if (pos != -1) removeBond(pos); 960 } 961 962 /** 963 * {@inheritDoc} 964 */ 965 @Override 966 public ILonePair removeLonePair(int position) { 967 ILonePair lp = lonePairs[position]; 968 for (int i = position; i < lonePairCount - 1; i++) { 969 lonePairs[i] = lonePairs[i + 1]; 970 } 971 lonePairs[lonePairCount - 1] = null; 972 lonePairCount--; 973 return lp; 974 } 975 976 /** 977 * {@inheritDoc} 978 */ 979 @Override 980 public void removeLonePair(ILonePair lonePair) { 981 int pos = indexOf(lonePair); 982 if (pos != -1) removeLonePair(pos); 983 } 984 985 /** 986 * {@inheritDoc} 987 */ 988 @Override 989 public ISingleElectron removeSingleElectron(int position) { 990 ISingleElectron se = singleElectrons[position]; 991 for (int i = position; i < singleElectronCount - 1; i++) { 992 singleElectrons[i] = singleElectrons[i + 1]; 993 } 994 singleElectrons[singleElectronCount - 1] = null; 995 singleElectronCount--; 996 return se; 997 } 998 999 /** 1000 * {@inheritDoc} 1001 */ 1002 @Override 1003 public void removeSingleElectron(ISingleElectron singleElectron) { 1004 int pos = indexOf(singleElectron); 1005 if (pos != -1) removeSingleElectron(pos); 1006 } 1007 1008 /** 1009 * {@inheritDoc} 1010 */ 1011 @Override 1012 public IElectronContainer removeElectronContainer(int number) { 1013 if (number < this.bondCount) return removeBond(number); 1014 number -= this.bondCount; 1015 if (number < this.lonePairCount) return removeLonePair(number); 1016 number -= this.lonePairCount; 1017 if (number < this.singleElectronCount) 1018 return removeSingleElectron(number); 1019 return null; 1020 } 1021 1022 /** 1023 * {@inheritDoc} 1024 */ 1025 @Override 1026 public void removeElectronContainer(IElectronContainer electronContainer) { 1027 if (electronContainer instanceof IBond) 1028 removeBond((IBond) electronContainer); 1029 else if (electronContainer instanceof ILonePair) 1030 removeLonePair((ILonePair) electronContainer); 1031 else if (electronContainer instanceof ISingleElectron) 1032 removeSingleElectron((ISingleElectron) electronContainer); 1033 } 1034 1035 /** 1036 * {@inheritDoc} 1037 */ 1038 @Override 1039 @Deprecated 1040 public void removeAtomAndConnectedElectronContainers(IAtom atom) { 1041 removeAtom(atom); 1042 } 1043 1044 /** 1045 * {@inheritDoc} 1046 */ 1047 @Override 1048 public void removeAtom(IAtom atom) { 1049 int position = getAtomNumber(atom); 1050 if (position != -1) { 1051 for (int i = 0; i < bondCount; i++) { 1052 if (bonds[i].contains(atom)) { 1053 removeBond(i); 1054 --i; 1055 } 1056 } 1057 for (int i = 0; i < lonePairCount; i++) { 1058 if (lonePairs[i].contains(atom)) { 1059 removeLonePair(i); 1060 --i; 1061 } 1062 } 1063 for (int i = 0; i < singleElectronCount; i++) { 1064 if (singleElectrons[i].contains(atom)) { 1065 removeSingleElectron(i); 1066 --i; 1067 } 1068 } 1069 List<IStereoElement> atomElements = new ArrayList<IStereoElement>(3); 1070 for (IStereoElement element : stereoElements) { 1071 if (element.contains(atom)) atomElements.add(element); 1072 } 1073 stereoElements.removeAll(atomElements); 1074 removeAtomOnly(position); 1075 } 1076 } 1077 1078 /** 1079 * {@inheritDoc} 1080 */ 1081 @Override 1082 public void removeAtom(int pos) { 1083 removeAtom(getAtom(pos)); 1084 } 1085 1086 /** 1087 * {@inheritDoc} 1088 */ 1089 @Override 1090 public void removeAllElements() { 1091 removeAllElectronContainers(); 1092 atoms = new IAtom[growArraySize]; 1093 atomCount = 0; 1094 stereoElements.clear(); 1095 } 1096 1097 /** 1098 * {@inheritDoc} 1099 */ 1100 @Override 1101 public void removeAllElectronContainers() { 1102 removeAllBonds(); 1103 lonePairs = new ILonePair[growArraySize]; 1104 singleElectrons = new ISingleElectron[growArraySize]; 1105 lonePairCount = 0; 1106 singleElectronCount = 0; 1107 } 1108 1109 /** 1110 * {@inheritDoc} 1111 */ 1112 @Override 1113 public void removeAllBonds() { 1114 bonds = new IBond[growArraySize]; 1115 bondCount = 0; 1116 } 1117 1118 /** 1119 * {@inheritDoc} 1120 */ 1121 @Override 1122 public void addBond(int atom1, int atom2, IBond.Order order, 1123 IBond.Stereo stereo) { 1124 IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order, stereo); 1125 addBond(bond); 1126 } 1127 1128 /** 1129 * {@inheritDoc} 1130 */ 1131 @Override 1132 public void addBond(int atom1, int atom2, IBond.Order order) { 1133 IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order); 1134 addBond(bond); 1135 } 1136 1137 /** 1138 * {@inheritDoc} 1139 */ 1140 @Override 1141 public void addLonePair(int atomID) { 1142 ILonePair lonePair = getBuilder().newInstance(ILonePair.class, atoms[atomID]); 1143 addLonePair(lonePair); 1144 } 1145 1146 /** 1147 * {@inheritDoc} 1148 */ 1149 @Override 1150 public void addSingleElectron(int atomID) { 1151 ISingleElectron singleElectron = getBuilder().newInstance(ISingleElectron.class, atoms[atomID]); 1152 addSingleElectron(singleElectron); 1153 } 1154 1155 /** 1156 * {@inheritDoc} 1157 */ 1158 @Override 1159 public boolean contains(IAtom atom) { 1160 for (int i = 0; i < getAtomCount(); i++) { 1161 if (atoms[i].equals(atom)) return true; 1162 } 1163 return false; 1164 } 1165 1166 /** 1167 * {@inheritDoc} 1168 */ 1169 @Override 1170 public boolean contains(IBond bond) { 1171 for (int i = 0; i < getBondCount(); i++) { 1172 if (bonds[i].equals(bond)) return true; 1173 } 1174 return false; 1175 } 1176 1177 /** 1178 * {@inheritDoc} 1179 */ 1180 @Override 1181 public boolean contains(ILonePair lonePair) { 1182 for (int i = 0; i < getLonePairCount(); i++) { 1183 if (lonePair == lonePairs[i]) return true; 1184 } 1185 return false; 1186 } 1187 1188 /** 1189 * {@inheritDoc} 1190 */ 1191 @Override 1192 public boolean contains(ISingleElectron singleElectron) { 1193 for (int i = 0; i < getSingleElectronCount(); i++) { 1194 if (singleElectron == singleElectrons[i]) return true; 1195 } 1196 return false; 1197 } 1198 1199 /** 1200 * {@inheritDoc} 1201 */ 1202 @Override 1203 public boolean contains(IElectronContainer electronContainer) { 1204 if (electronContainer instanceof IBond) 1205 return contains((IBond) electronContainer); 1206 if (electronContainer instanceof ILonePair) 1207 return contains((ILonePair) electronContainer); 1208 if (electronContainer instanceof ISingleElectron) 1209 return contains((SingleElectron) electronContainer); 1210 return false; 1211 } 1212 1213 /** 1214 * {@inheritDoc} 1215 */ 1216 @Override 1217 public String toString() { 1218 StringBuffer stringContent = new StringBuffer(64); 1219 stringContent.append("AtomContainer("); 1220 stringContent.append(this.hashCode()); 1221 if (getAtomCount() > 0) { 1222 stringContent.append(", #A:").append(getAtomCount()); 1223 for (int i = 0; i < getAtomCount(); i++) { 1224 stringContent.append(", ").append(getAtom(i).toString()); 1225 } 1226 } 1227 if (getBondCount() > 0) { 1228 stringContent.append(", #B:").append(getBondCount()); 1229 for (int i = 0; i < getBondCount(); i++) { 1230 stringContent.append(", ").append(getBond(i).toString()); 1231 } 1232 } 1233 if (getLonePairCount() > 0) { 1234 stringContent.append(", #LP:").append(getLonePairCount()); 1235 for (int i = 0; i < getLonePairCount(); i++) { 1236 stringContent.append(", ").append(getLonePair(i).toString()); 1237 } 1238 } 1239 if (getSingleElectronCount() > 0) { 1240 stringContent.append(", #SE:").append(getSingleElectronCount()); 1241 for (int i = 0; i < getSingleElectronCount(); i++) { 1242 stringContent.append(", ").append(getSingleElectron(i).toString()); 1243 } 1244 } 1245 if (stereoElements.size() > 0) { 1246 stringContent.append(", ST:[#").append(stereoElements.size()); 1247 for (IStereoElement elements : stereoElements) { 1248 stringContent.append(", ").append(elements.toString()); 1249 } 1250 stringContent.append(']'); 1251 } 1252 stringContent.append(')'); 1253 return stringContent.toString(); 1254 } 1255 1256 /** 1257 * {@inheritDoc} 1258 */ 1259 @Override 1260 public IAtomContainer clone() throws CloneNotSupportedException { 1261 1262 // this is pretty wasteful as we need to delete most the data 1263 // we can't simply create an empty instance as the sub classes (e.g. AminoAcid) 1264 // would have a ClassCastException when they invoke clone 1265 IAtomContainer clone = (IAtomContainer) super.clone(); 1266 1267 // remove existing elements - we need to set the stereo elements list as list.clone() doesn't 1268 // work as expected and will also remove all elements from the original 1269 clone.setStereoElements(new ArrayList<IStereoElement>(stereoElements.size())); 1270 clone.removeAllElements(); 1271 1272 // create a mapping of the original atoms/bonds to the cloned atoms/bonds 1273 // we need this mapping to correctly clone bonds, single/paired electrons 1274 // and stereo elements 1275 // - the expected size stop the map be resized - method from Google Guava 1276 Map<IAtom, IAtom> atomMap = new HashMap<IAtom, IAtom>(atomCount >= 3 ? atomCount + atomCount / 3 1277 : atomCount + 1); 1278 Map<IBond, IBond> bondMap = new HashMap<IBond, IBond>(bondCount >= 3 ? bondCount + bondCount / 3 1279 : bondCount + 1); 1280 1281 // clone atoms 1282 IAtom[] atoms = new IAtom[this.atomCount]; 1283 for (int i = 0; i < atoms.length; i++) { 1284 1285 atoms[i] = (IAtom) this.atoms[i].clone(); 1286 atomMap.put(this.atoms[i], atoms[i]); 1287 } 1288 clone.setAtoms(atoms); 1289 1290 // clone bonds using a the mappings from the original to the clone 1291 IBond[] bonds = new IBond[this.bondCount]; 1292 for (int i = 0; i < bonds.length; i++) { 1293 1294 IBond original = this.bonds[i]; 1295 IBond bond = (IBond) original.clone(); 1296 int n = bond.getAtomCount(); 1297 IAtom[] members = new IAtom[n]; 1298 1299 for (int j = 0; j < n; j++) { 1300 members[j] = atomMap.get(original.getAtom(j)); 1301 } 1302 1303 bond.setAtoms(members); 1304 bondMap.put(this.bonds[i], bond); 1305 bonds[i] = bond; 1306 } 1307 clone.setBonds(bonds); 1308 1309 // clone lone pairs (we can't use an array to buffer as there is no setLonePairs()) 1310 for (int i = 0; i < lonePairCount; i++) { 1311 1312 ILonePair original = this.lonePairs[i]; 1313 ILonePair pair = (ILonePair) original.clone(); 1314 1315 if (pair.getAtom() != null) 1316 pair.setAtom(atomMap.get(original.getAtom())); 1317 1318 clone.addLonePair(pair); 1319 } 1320 1321 // clone single electrons (we can't use an array to buffer as there is no setSingleElectrons()) 1322 for (int i = 0; i < singleElectronCount; i++) { 1323 1324 ISingleElectron original = this.singleElectrons[i]; 1325 ISingleElectron electron = (ISingleElectron) original.clone(); 1326 1327 if (electron.getAtom() != null) 1328 electron.setAtom(atomMap.get(original.getAtom())); 1329 1330 clone.addSingleElectron(electron); 1331 } 1332 1333 // map each stereo element to a new instance in the clone 1334 for (IStereoElement element : stereoElements) { 1335 clone.addStereoElement(element.map(atomMap, bondMap)); 1336 } 1337 1338 // update sgroups 1339 Collection<Sgroup> sgroups = getProperty(CDKConstants.CTAB_SGROUPS); 1340 if (sgroups != null) { 1341 Map<IChemObject,IChemObject> replace = new HashMap<>(); 1342 replace.putAll(atomMap); 1343 replace.putAll(bondMap); 1344 clone.setProperty(CDKConstants.CTAB_SGROUPS, 1345 SgroupManipulator.copy(sgroups, replace)); 1346 } 1347 1348 1349 return clone; 1350 } 1351 1352 /** 1353 * Generic grow function, expand an array by a varried amount to have 1354 * enough (required) space. 1355 * 1356 * @param array the array to expand 1357 * @param required the minimum required space 1358 * @param <T> array type 1359 * @return the expanded array 1360 */ 1361 private static <T> T[] grow(T[] array, int required) { 1362 int oldCapacity = array.length; 1363 // x1.5: 20, 30, 45, 67, 100, 150, 225, 337, 505, etc 1364 int newCapacity = oldCapacity == 0 ? DEFAULT_CAPACITY 1365 : oldCapacity + (oldCapacity >> 1); 1366 if (newCapacity < required) 1367 newCapacity = required; 1368 return Arrays.copyOf(array, newCapacity); 1369 } 1370 1371 /** 1372 * Ensure there is enough space to accommodate the specified number of 1373 * atoms. 1374 * 1375 * @param required total number of atoms (inc. already used) 1376 */ 1377 private void ensureAtomCapacity(int required) { 1378 if (required > atoms.length) 1379 atoms = grow(atoms, required); 1380 } 1381 1382 /** 1383 * Ensure there is enough space to accommodate the specified number of 1384 * bonds. 1385 * 1386 * @param required total number of bonds (inc. already used) 1387 */ 1388 private void ensureBondCapacity(int required) { 1389 if (required > bonds.length) 1390 bonds = grow(bonds, required); 1391 } 1392 1393 /** 1394 * Ensure there is enough space to accommodate the specified number of 1395 * electrons. 1396 * 1397 * @param required total number of electrons (inc. already used) 1398 */ 1399 private void ensureElectronCapacity(int required) { 1400 if (required > singleElectrons.length) 1401 singleElectrons = grow(singleElectrons, required); 1402 } 1403 1404 /** 1405 * Ensure there is enough space to accommodate the specified number of 1406 * lone pairs. 1407 * 1408 * @param required total number of lone pairs (inc. already used) 1409 */ 1410 private void ensureLonePairCapacity(int required) { 1411 if (required > lonePairs.length) 1412 lonePairs = grow(lonePairs, required); 1413 } 1414 1415 /** 1416 * {@inheritDoc} 1417 */ 1418 @Override 1419 public void stateChanged(IChemObjectChangeEvent event) { 1420 // ignored 1421 } 1422 1423 /** 1424 * {@inheritDoc} 1425 */ 1426 @Override 1427 public boolean isEmpty() { 1428 return atomCount == 0; 1429 } 1430 1431 /** 1432 * {@inheritDoc} 1433 */ 1434 @Override 1435 public String getTitle() { 1436 return getProperty(CDKConstants.TITLE); 1437 } 1438 1439 /** 1440 * {@inheritDoc} 1441 */ 1442 @Override 1443 public void setTitle(String title) { 1444 setProperty(CDKConstants.TITLE, title); 1445 } 1446 1447 /** 1448 * The inner AtomIterator class. 1449 */ 1450 private class AtomIterator implements Iterator<IAtom> { 1451 1452 private int pointer = 0; 1453 1454 @Override 1455 public boolean hasNext() { 1456 return pointer < atomCount; 1457 } 1458 1459 @Override 1460 public IAtom next() { 1461 return atoms[pointer++]; 1462 } 1463 1464 @Override 1465 public void remove() { 1466 removeAtomOnly(--pointer); 1467 } 1468 1469 } 1470 1471 /** 1472 * The inner BondIterator class. 1473 */ 1474 private class BondIterator implements Iterator<IBond> { 1475 1476 private int pointer = 0; 1477 1478 @Override 1479 public boolean hasNext() { 1480 return pointer < bondCount; 1481 } 1482 1483 @Override 1484 public IBond next() { 1485 return bonds[pointer++]; 1486 } 1487 1488 @Override 1489 public void remove() { 1490 removeBond(--pointer); 1491 } 1492 1493 } 1494 1495 /** 1496 * The inner LonePairIterator class. 1497 */ 1498 private class LonePairIterator implements Iterator<ILonePair> { 1499 1500 private int pointer = 0; 1501 1502 @Override 1503 public boolean hasNext() { 1504 return pointer < lonePairCount; 1505 } 1506 1507 @Override 1508 public ILonePair next() { 1509 return lonePairs[pointer++]; 1510 } 1511 1512 @Override 1513 public void remove() { 1514 removeLonePair(--pointer); 1515 } 1516 1517 } 1518 1519 /** 1520 * The inner SingleElectronIterator class. 1521 */ 1522 private class SingleElectronIterator implements Iterator<ISingleElectron> { 1523 1524 private int pointer = 0; 1525 1526 @Override 1527 public boolean hasNext() { 1528 return pointer < singleElectronCount; 1529 } 1530 1531 @Override 1532 public ISingleElectron next() { 1533 return singleElectrons[pointer++]; 1534 } 1535 1536 @Override 1537 public void remove() { 1538 removeSingleElectron(--pointer); 1539 } 1540 1541 } 1542 1543 /** 1544 * The inner ElectronContainerIterator class. 1545 */ 1546 private class ElectronContainerIterator implements Iterator<IElectronContainer> { 1547 1548 private int pointer = 0; 1549 1550 @Override 1551 public boolean hasNext() { 1552 return pointer < (bondCount + lonePairCount + singleElectronCount); 1553 } 1554 1555 @Override 1556 public IElectronContainer next() { 1557 if (pointer < bondCount) 1558 return bonds[pointer++]; 1559 else if (pointer < bondCount + lonePairCount) 1560 return lonePairs[(pointer++) - bondCount]; 1561 else if (pointer < bondCount + lonePairCount + singleElectronCount) 1562 return singleElectrons[(pointer++) - bondCount - lonePairCount]; 1563 return null; 1564 } 1565 1566 @Override 1567 public void remove() { 1568 if (pointer <= bondCount) 1569 removeBond(--pointer); 1570 else if (pointer <= bondCount + lonePairCount) 1571 removeLonePair((--pointer) - bondCount); 1572 else if (pointer <= bondCount + lonePairCount + singleElectronCount) 1573 removeSingleElectron((--pointer) - bondCount - lonePairCount); 1574 } 1575 1576 } 1577 1578 } 1579