All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openscience.cdk.AtomContainer Maven / Gradle / Ivy

/* Copyright (C) 1997-2007  Christoph Steinbeck
 *
 *  Contact: [email protected]
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.openscience.cdk;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.openscience.cdk.exception.NoSuchAtomException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectChangeEvent;
import org.openscience.cdk.interfaces.IChemObjectListener;
import org.openscience.cdk.interfaces.IElectronContainer;
import org.openscience.cdk.interfaces.ILonePair;
import org.openscience.cdk.interfaces.ISingleElectron;
import org.openscience.cdk.interfaces.IStereoElement;
import org.openscience.cdk.interfaces.IBond.Order;

/**
 * Base class for all chemical objects that maintain a list of Atoms and
 * ElectronContainers. 

*

* Looping over all Bonds in the AtomContainer is typically done like:

 * Iterator iter = atomContainer.bonds();
 * while (iter.hasNext()) {
 *   IBond aBond = (IBond) iter.next();
 * }
 * 
* * @author steinbeck * @cdk.module data * @cdk.githash * @cdk.created 2000-10-02 */ public class AtomContainer extends ChemObject implements IAtomContainer, IChemObjectListener, Serializable, Cloneable { private static final int DEFAULT_CAPACITY = 20; /** * Determines if a de-serialized object is compatible with this class. *

* This value must only be changed if and only if the new version * of this class is incompatible with the old version. See Sun docs * for details. */ private static final long serialVersionUID = 5678100348445919254L; /** * Number of atoms contained by this object. */ protected int atomCount; /** * Number of bonds contained by this object. */ protected int bondCount; /** * Number of lone pairs contained by this object. */ protected int lonePairCount; /** * Number of single electrons contained by this object. */ protected int singleElectronCount; /** * Amount by which the bond and atom arrays grow when elements are added and * the arrays are not large enough for that. */ protected int growArraySize = 10; /** * Internal array of atoms. */ protected IAtom[] atoms; /** * Internal array of bonds. */ protected IBond[] bonds; /** * Internal array of lone pairs. */ protected ILonePair[] lonePairs; /** * Internal array of single electrons. */ protected ISingleElectron[] singleElectrons; /** * Internal list of atom parities. */ protected Set stereoElements; /** * Constructs an empty AtomContainer. */ public AtomContainer() { this(0, 0, 0, 0); } /** * Constructs an AtomContainer with a copy of the atoms and electronContainers * of another AtomContainer (A shallow copy, i.e., with the same objects as in * the original AtomContainer). * * @param container An AtomContainer to copy the atoms and electronContainers from */ public AtomContainer(IAtomContainer container) { this.atomCount = container.getAtomCount(); this.bondCount = container.getBondCount(); this.lonePairCount = container.getLonePairCount(); this.singleElectronCount = container.getSingleElectronCount(); this.atoms = new IAtom[this.atomCount]; this.bonds = new IBond[this.bondCount]; this.lonePairs = new ILonePair[this.lonePairCount]; this.singleElectrons = new ISingleElectron[this.singleElectronCount]; stereoElements = new HashSet(atomCount / 2); for (IStereoElement element : container.stereoElements()) { addStereoElement(element); } for (int f = 0; f < container.getAtomCount(); f++) { atoms[f] = container.getAtom(f); container.getAtom(f).addListener(this); } for (int f = 0; f < this.bondCount; f++) { bonds[f] = container.getBond(f); container.getBond(f).addListener(this); } for (int f = 0; f < this.lonePairCount; f++) { lonePairs[f] = container.getLonePair(f); container.getLonePair(f).addListener(this); } for (int f = 0; f < this.singleElectronCount; f++) { singleElectrons[f] = container.getSingleElectron(f); container.getSingleElectron(f).addListener(this); } } /** * Constructs an empty AtomContainer that will contain a certain number of * atoms and electronContainers. It will set the starting array lengths to the * defined values, but will not create any Atom or ElectronContainer's. * * @param atomCount Number of atoms to be in this container * @param bondCount Number of bonds to be in this container * @param lpCount Number of lone pairs to be in this container * @param seCount Number of single electrons to be in this container */ public AtomContainer(int atomCount, int bondCount, int lpCount, int seCount) { this.atomCount = 0; this.bondCount = 0; this.lonePairCount = 0; this.singleElectronCount = 0; atoms = new IAtom[atomCount]; bonds = new IBond[bondCount]; lonePairs = new ILonePair[lpCount]; singleElectrons = new ISingleElectron[seCount]; stereoElements = new HashSet(atomCount / 2); } /** * {@inheritDoc} */ @Override public void addStereoElement(IStereoElement element) { stereoElements.add(element); } /** * {@inheritDoc} */ @Override public void setStereoElements(List elements) { this.stereoElements = new HashSet(); this.stereoElements.addAll(elements); } /** * {@inheritDoc} */ @Override public Iterable stereoElements() { return Collections.unmodifiableSet(stereoElements); } /** * {@inheritDoc} */ @Override public void setAtoms(IAtom[] newAtoms) { // unregister this as listener with the old atoms for (int i = 0; i < atomCount; i++) { this.atoms[i].removeListener(this); } for (IAtom atom : newAtoms) { atom.addListener(this); } ensureAtomCapacity(newAtoms.length); System.arraycopy(newAtoms, 0, this.atoms, 0, newAtoms.length); if (newAtoms.length < this.atoms.length) Arrays.fill(atoms, newAtoms.length, this.atoms.length, null); this.atomCount = newAtoms.length; notifyChanged(); } /** * {@inheritDoc} */ @Override public void setBonds(IBond[] newBonds) { for (int i = 0; i < bondCount; i++) { this.bonds[i].removeListener(this); } for (IBond bond : newBonds) { bond.addListener(this); } ensureBondCapacity(newBonds.length); System.arraycopy(newBonds, 0, this.bonds, 0, newBonds.length); if (newBonds.length < this.bonds.length) Arrays.fill(bonds, newBonds.length, this.bonds.length, null); this.bondCount = newBonds.length; } /** * {@inheritDoc} */ @Override public void setAtom(int idx, IAtom atom) { if (idx >= atomCount) throw new IndexOutOfBoundsException("No atom at index: " + idx); int aidx = indexOf(atom); if (aidx >= 0) throw new IllegalArgumentException("Atom already in container at index: " + idx); final IAtom oldAtom = atoms[idx]; atoms[idx] = atom; atom.addListener(this); oldAtom.removeListener(this); // replace in electron containers for (IBond bond : bonds()) { for (int i = 0; i < bond.getAtomCount(); i++) { if (oldAtom.equals(bond.getAtom(i))) { bond.setAtom(atom, i); } } } for (ISingleElectron ec : singleElectrons()) { if (oldAtom.equals(ec.getAtom())) ec.setAtom(atom); } for (ILonePair lp : lonePairs()) { if (oldAtom.equals(lp.getAtom())) lp.setAtom(atom); } // update stereo List oldStereo = null; List newStereo = null; for (IStereoElement se : stereoElements()) { if (se.contains(oldAtom)) { if (oldStereo == null) { oldStereo = new ArrayList<>(); newStereo = new ArrayList<>(); } oldStereo.add(se); Map amap = Collections.singletonMap(oldAtom, atom); Map bmap = Collections.emptyMap(); newStereo.add(se.map(amap, bmap)); } } if (oldStereo != null) { stereoElements.removeAll(oldStereo); stereoElements.addAll(newStereo); } notifyChanged(); } /** * {@inheritDoc} */ @Override public IAtom getAtom(int idx) { if (idx < 0 || idx >= atomCount) throw new IndexOutOfBoundsException("Atom index out of bounds: 0 <= " + idx + " < " + atomCount); return atoms[idx]; } /** * {@inheritDoc} */ @Override public IBond getBond(int idx) { if (idx < 0 || idx >= bondCount) throw new IndexOutOfBoundsException("Bond index out of bounds: 0 <= " + idx + " < " + bondCount); return bonds[idx]; } /** * {@inheritDoc} */ @Override public ILonePair getLonePair(int idx) { if (idx < 0 || idx >= lonePairCount) throw new IndexOutOfBoundsException("Lone Pair index out of bounds: 0 <= " + idx + " < " + lonePairCount); return lonePairs[idx]; } /** * {@inheritDoc} */ @Override public ISingleElectron getSingleElectron(int idx) { if (idx < 0 || idx >= singleElectronCount) throw new IndexOutOfBoundsException("Single Electrong index out of bounds: 0 <= " + idx + " < " + singleElectronCount); return singleElectrons[idx]; } /** * {@inheritDoc} */ @Override public Iterable atoms() { return new Iterable() { @Override public Iterator iterator() { return new AtomIterator(); } }; } /** * {@inheritDoc} */ @Override public Iterable bonds() { return new Iterable() { @Override public Iterator iterator() { return new BondIterator(); } }; } /** * {@inheritDoc} */ @Override public Iterable lonePairs() { return new Iterable() { @Override public Iterator iterator() { return new LonePairIterator(); } }; } /** * {@inheritDoc} */ @Override public Iterable singleElectrons() { return new Iterable() { @Override public Iterator iterator() { return new SingleElectronIterator(); } }; } /** * {@inheritDoc} */ @Override public Iterable electronContainers() { return new Iterable() { @Override public Iterator iterator() { return new ElectronContainerIterator(); } }; } /** * {@inheritDoc} */ @Override public IAtom getFirstAtom() { return atoms[0]; } /** * {@inheritDoc} */ @Override public IAtom getLastAtom() { return getAtomCount() > 0 ? (IAtom) atoms[getAtomCount() - 1] : null; } /** * {@inheritDoc} */ @Override public int getAtomNumber(IAtom atom) { return indexOf(atom); } /** * {@inheritDoc} */ @Override public int getBondNumber(IAtom atom1, IAtom atom2) { return indexOf(getBond(atom1, atom2)); } /** * {@inheritDoc} */ @Override public int getBondNumber(IBond bond) { return indexOf(bond); } /** * {@inheritDoc} */ @Override public int getLonePairNumber(ILonePair lonePair) { return indexOf(lonePair); } /** * {@inheritDoc} */ @Override public int getSingleElectronNumber(ISingleElectron singleElectron) { return indexOf(singleElectron); } /** * {@inheritDoc} */ @Override public int indexOf(IAtom atom) { for (int i = 0; i < atomCount; i++) { if (atoms[i].equals(atom)) return i; } return -1; } /** * {@inheritDoc} */ @Override public int indexOf(IBond bond) { for (int i = 0; i < bondCount; i++) { if (bonds[i].equals(bond)) return i; } return -1; } /** * {@inheritDoc} */ @Override public int indexOf(ISingleElectron electron) { for (int i = 0; i < singleElectronCount; i++) { if (singleElectrons[i] == electron) return i; } return -1; } /** * {@inheritDoc} */ @Override public int indexOf(ILonePair pair) { for (int i = 0; i < lonePairCount; i++) { if (lonePairs[i] == pair) return i; } return -1; } /** * {@inheritDoc} */ @Override public IElectronContainer getElectronContainer(int number) { if (number < this.bondCount) return bonds[number]; number -= this.bondCount; if (number < this.lonePairCount) return lonePairs[number]; number -= this.lonePairCount; if (number < this.singleElectronCount) return singleElectrons[number]; return null; } /** * {@inheritDoc} */ @Override public IBond getBond(IAtom atom1, IAtom atom2) { for (int i = 0; i < getBondCount(); i++) { if (bonds[i].contains(atom1) && bonds[i].getOther(atom1).equals(atom2)) { return bonds[i]; } } return null; } /** * {@inheritDoc} */ @Override public int getAtomCount() { return this.atomCount; } /** * {@inheritDoc} */ @Override public int getBondCount() { return this.bondCount; } /** * {@inheritDoc} */ @Override public int getLonePairCount() { return this.lonePairCount; } /** * {@inheritDoc} */ @Override public int getSingleElectronCount() { return this.singleElectronCount; } /** * {@inheritDoc} */ @Override public int getElectronContainerCount() { return this.bondCount + this.lonePairCount + this.singleElectronCount; } /** * {@inheritDoc} */ @Override public List getConnectedAtomsList(IAtom atom) { List atomsList = new ArrayList<>(4); for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) atomsList.add(bonds[i].getOther(atom)); } if (atomsList.isEmpty() && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return atomsList; } /** * {@inheritDoc} */ @Override public List getConnectedBondsList(IAtom atom) { List bondsList = new ArrayList<>(4); for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) bondsList.add(bonds[i]); } if (bondsList.isEmpty() && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return bondsList; } /** * {@inheritDoc} */ @Override public List getConnectedLonePairsList(IAtom atom) { List lps = new ArrayList<>(2); for (int i = 0; i < lonePairCount; i++) { if (lonePairs[i].contains(atom)) lps.add(lonePairs[i]); } if (lps.isEmpty() && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return lps; } /** * {@inheritDoc} */ @Override public List getConnectedSingleElectronsList(IAtom atom) { List ses = new ArrayList<>(2); for (int i = 0; i < singleElectronCount; i++) { if (singleElectrons[i].contains(atom)) ses.add(singleElectrons[i]); } if (ses.isEmpty() && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return ses; } /** * {@inheritDoc} */ @Override public List getConnectedElectronContainersList(IAtom atom) { List ecs = new ArrayList<>(4); for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) ecs.add(bonds[i]); } for (int i = 0; i < lonePairCount; i++) { if (lonePairs[i].contains(atom)) ecs.add(lonePairs[i]); } for (int i = 0; i < singleElectronCount; i++) { if (singleElectrons[i].contains(atom)) ecs.add(singleElectrons[i]); } if (ecs.isEmpty() && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return ecs; } /** * {@inheritDoc} */ @Override public int getConnectedBondsCount(IAtom atom) { int count = 0; for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) ++count; } if (count == 0 && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return count; } /** * {@inheritDoc} */ @Override public int getConnectedAtomsCount(IAtom atom) { return getConnectedBondsCount(atom); } /** * {@inheritDoc} */ @Override public int getConnectedBondsCount(int idx) { final IAtom atom = getAtom(idx); int count = 0; for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) ++count; } return count; } /** * {@inheritDoc} */ @Override public int getConnectedLonePairsCount(IAtom atom) { int count = 0; for (int i = 0; i < lonePairCount; i++) { if (lonePairs[i].contains(atom)) ++count; } if (count == 0 && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return count; } /** * {@inheritDoc} */ @Override public int getConnectedSingleElectronsCount(IAtom atom) { int count = 0; for (int i = 0; i < singleElectronCount; i++) { if (singleElectrons[i].contains(atom)) ++count; } if (count == 0 && !contains(atom)) throw new NoSuchAtomException("Atom does not belong to the container!"); return count; } /** * {@inheritDoc} */ @Override public double getBondOrderSum(IAtom atom) { double count = 0; for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) { IBond.Order order = bonds[i].getOrder(); if (order != null) { count += order.numeric(); } } } return count; } /** * {@inheritDoc} */ @Override public Order getMaximumBondOrder(IAtom atom) { IBond.Order max = null; for (IBond bond : bonds()) { if (!bond.contains(atom)) continue; if (max == null || bond.getOrder().numeric() > max.numeric()) { max = bond.getOrder(); } } if (max == null) { if (!contains(atom)) throw new NoSuchAtomException("Atom does not belong to this container!"); if (atom.getImplicitHydrogenCount() != null && atom.getImplicitHydrogenCount() > 0) max = Order.SINGLE; else max = Order.UNSET; } return max; } /** * {@inheritDoc} */ @Override public Order getMinimumBondOrder(IAtom atom) { IBond.Order min = null; for (IBond bond : bonds()) { if (!bond.contains(atom)) continue; if (min == null || bond.getOrder().numeric() < min.numeric()) { min = bond.getOrder(); } } if (min == null) { if (!contains(atom)) throw new NoSuchAtomException("Atom does not belong to this container!"); if (atom.getImplicitHydrogenCount() != null && atom.getImplicitHydrogenCount() > 0) min = Order.SINGLE; else min = Order.UNSET; } return min; } /** * {@inheritDoc} */ @Override public void add(IAtomContainer that) { atoms = Arrays.copyOf(atoms, atomCount + that.getAtomCount()); bonds = Arrays.copyOf(bonds, bondCount + that.getBondCount()); for (IAtom atom : that.atoms()) atom.setFlag(CDKConstants.VISITED, false); for (IBond bond : that.bonds()) bond.setFlag(CDKConstants.VISITED, false); for (IAtom atom : this.atoms()) atom.setFlag(CDKConstants.VISITED, true); for (IBond bond : this.bonds()) bond.setFlag(CDKConstants.VISITED, true); for (IAtom atom : that.atoms()) { if (!atom.getFlag(CDKConstants.VISITED)) { atom.setFlag(CDKConstants.VISITED, true); atoms[atomCount++] = atom; } } for (IBond bond : that.bonds()) { if (!bond.getFlag(CDKConstants.VISITED)) { bond.setFlag(CDKConstants.VISITED, true); bonds[bondCount++] = bond; } } for (ILonePair lp : that.lonePairs()) { if (!contains(lp)) { addLonePair(lp); } } for (ISingleElectron se : that.singleElectrons()) { if (!contains(se)) { addSingleElectron(se); } } for (IStereoElement se : that.stereoElements()) stereoElements.add(se); notifyChanged(); } /** * {@inheritDoc} */ @Override public void addAtom(IAtom atom) { if (contains(atom)) { return; } ensureAtomCapacity(atomCount + 1); atom.addListener(this); atoms[atomCount++] = atom; notifyChanged(); } /** * {@inheritDoc} */ @Override public void addBond(IBond bond) { ensureBondCapacity(bondCount + 1); bonds[bondCount++] = bond; notifyChanged(); } /** * {@inheritDoc} */ @Override public void addLonePair(ILonePair lonePair) { ensureLonePairCapacity(lonePairCount + 1); lonePairs[lonePairCount++] = lonePair; notifyChanged(); } /** * {@inheritDoc} */ @Override public void addSingleElectron(ISingleElectron singleElectron) { ensureElectronCapacity(singleElectronCount + 1); singleElectrons[singleElectronCount++] = singleElectron; notifyChanged(); } /** * {@inheritDoc} */ @Override public void addElectronContainer(IElectronContainer electronContainer) { if (electronContainer instanceof IBond) this.addBond((IBond) electronContainer); if (electronContainer instanceof ILonePair) this.addLonePair((ILonePair) electronContainer); if (electronContainer instanceof ISingleElectron) this.addSingleElectron((ISingleElectron) electronContainer); } /** * {@inheritDoc} */ @Override public void remove(IAtomContainer atomContainer) { for (int f = 0; f < atomContainer.getAtomCount(); f++) { removeAtomOnly(atomContainer.getAtom(f)); } for (int f = 0; f < atomContainer.getBondCount(); f++) { removeBond(atomContainer.getBond(f)); } for (int f = 0; f < atomContainer.getLonePairCount(); f++) { removeLonePair(atomContainer.getLonePair(f)); } for (int f = 0; f < atomContainer.getSingleElectronCount(); f++) { removeSingleElectron(atomContainer.getSingleElectron(f)); } } /** * {@inheritDoc} */ @Override public void removeAtomOnly(int position) { atoms[position].removeListener(this); for (int i = position; i < atomCount - 1; i++) { atoms[i] = atoms[i + 1]; } atoms[atomCount - 1] = null; atomCount--; notifyChanged(); } /** * {@inheritDoc} */ @Override public void removeAtomOnly(IAtom atom) { int position = getAtomNumber(atom); if (position != -1) { removeAtomOnly(position); } } /** * {@inheritDoc} */ @Override public IBond removeBond(int position) { IBond bond = bonds[position]; bond.removeListener(this); for (int i = position; i < bondCount - 1; i++) { bonds[i] = bonds[i + 1]; } bonds[bondCount - 1] = null; bondCount--; notifyChanged(); return bond; } /** * {@inheritDoc} */ @Override public IBond removeBond(IAtom atom1, IAtom atom2) { int pos = indexOf(getBond(atom1, atom2)); IBond bond = null; if (pos != -1) { bond = bonds[pos]; removeBond(pos); } return bond; } /** * {@inheritDoc} */ @Override public void removeBond(IBond bond) { int pos = getBondNumber(bond); if (pos != -1) removeBond(pos); } /** * {@inheritDoc} */ @Override public ILonePair removeLonePair(int position) { ILonePair lp = lonePairs[position]; lp.removeListener(this); for (int i = position; i < lonePairCount - 1; i++) { lonePairs[i] = lonePairs[i + 1]; } lonePairs[lonePairCount - 1] = null; lonePairCount--; notifyChanged(); return lp; } /** * {@inheritDoc} */ @Override public void removeLonePair(ILonePair lonePair) { int pos = indexOf(lonePair); if (pos != -1) removeLonePair(pos); } /** * {@inheritDoc} */ @Override public ISingleElectron removeSingleElectron(int position) { ISingleElectron se = singleElectrons[position]; se.removeListener(this); for (int i = position; i < singleElectronCount - 1; i++) { singleElectrons[i] = singleElectrons[i + 1]; } singleElectrons[singleElectronCount - 1] = null; singleElectronCount--; notifyChanged(); return se; } /** * {@inheritDoc} */ @Override public void removeSingleElectron(ISingleElectron singleElectron) { int pos = indexOf(singleElectron); if (pos != -1) removeSingleElectron(pos); } /** * {@inheritDoc} */ @Override public IElectronContainer removeElectronContainer(int number) { if (number < this.bondCount) return removeBond(number); number -= this.bondCount; if (number < this.lonePairCount) return removeLonePair(number); number -= this.lonePairCount; if (number < this.singleElectronCount) return removeSingleElectron(number); return null; } /** * {@inheritDoc} */ @Override public void removeElectronContainer(IElectronContainer electronContainer) { if (electronContainer instanceof IBond) removeBond((IBond) electronContainer); else if (electronContainer instanceof ILonePair) removeLonePair((ILonePair) electronContainer); else if (electronContainer instanceof ISingleElectron) removeSingleElectron((ISingleElectron) electronContainer); } /** * {@inheritDoc} */ @Override @Deprecated public void removeAtomAndConnectedElectronContainers(IAtom atom) { removeAtom(atom); } /** * {@inheritDoc} */ @Override public void removeAtom(IAtom atom) { int position = getAtomNumber(atom); if (position != -1) { for (int i = 0; i < bondCount; i++) { if (bonds[i].contains(atom)) { removeBond(i); --i; } } for (int i = 0; i < lonePairCount; i++) { if (lonePairs[i].contains(atom)) { removeLonePair(i); --i; } } for (int i = 0; i < singleElectronCount; i++) { if (singleElectrons[i].contains(atom)) { removeSingleElectron(i); --i; } } List atomElements = new ArrayList(3); for (IStereoElement element : stereoElements) { if (element.contains(atom)) atomElements.add(element); } stereoElements.removeAll(atomElements); removeAtomOnly(position); } notifyChanged(); } /** * {@inheritDoc} */ @Override public void removeAtom(int pos) { removeAtom(getAtom(pos)); } /** * {@inheritDoc} */ @Override public void removeAllElements() { removeAllElectronContainers(); for (int f = 0; f < getAtomCount(); f++) { getAtom(f).removeListener(this); } atoms = new IAtom[growArraySize]; atomCount = 0; stereoElements.clear(); notifyChanged(); } /** * {@inheritDoc} */ @Override public void removeAllElectronContainers() { removeAllBonds(); for (int f = 0; f < getLonePairCount(); f++) { getLonePair(f).removeListener(this); } for (int f = 0; f < getSingleElectronCount(); f++) { getSingleElectron(f).removeListener(this); } lonePairs = new ILonePair[growArraySize]; singleElectrons = new ISingleElectron[growArraySize]; lonePairCount = 0; singleElectronCount = 0; notifyChanged(); } /** * {@inheritDoc} */ @Override public void removeAllBonds() { for (int f = 0; f < getBondCount(); f++) { getBond(f).removeListener(this); } bonds = new IBond[growArraySize]; bondCount = 0; notifyChanged(); } /** * {@inheritDoc} */ @Override public void addBond(int atom1, int atom2, IBond.Order order, IBond.Stereo stereo) { IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order, stereo); addBond(bond); /* * no notifyChanged() here because addBond(bond) does it already */ } /** * {@inheritDoc} */ @Override public void addBond(int atom1, int atom2, IBond.Order order) { IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order); addBond(bond); /* * no notifyChanged() here because addBond(bond) does it already */ } /** * {@inheritDoc} */ @Override public void addLonePair(int atomID) { ILonePair lonePair = getBuilder().newInstance(ILonePair.class, atoms[atomID]); lonePair.addListener(this); addLonePair(lonePair); /* * no notifyChanged() here because addElectronContainer() does it * already */ } /** * {@inheritDoc} */ @Override public void addSingleElectron(int atomID) { ISingleElectron singleElectron = getBuilder().newInstance(ISingleElectron.class, atoms[atomID]); singleElectron.addListener(this); addSingleElectron(singleElectron); /* * no notifyChanged() here because addSingleElectron() does it already */ } /** * {@inheritDoc} */ @Override public boolean contains(IAtom atom) { for (int i = 0; i < getAtomCount(); i++) { if (atoms[i].equals(atom)) return true; } return false; } /** * {@inheritDoc} */ @Override public boolean contains(IBond bond) { for (int i = 0; i < getBondCount(); i++) { if (bonds[i].equals(bond)) return true; } return false; } /** * {@inheritDoc} */ @Override public boolean contains(ILonePair lonePair) { for (int i = 0; i < getLonePairCount(); i++) { if (lonePair == lonePairs[i]) return true; } return false; } /** * {@inheritDoc} */ @Override public boolean contains(ISingleElectron singleElectron) { for (int i = 0; i < getSingleElectronCount(); i++) { if (singleElectron == singleElectrons[i]) return true; } return false; } /** * {@inheritDoc} */ @Override public boolean contains(IElectronContainer electronContainer) { if (electronContainer instanceof IBond) return contains((IBond) electronContainer); if (electronContainer instanceof ILonePair) return contains((ILonePair) electronContainer); if (electronContainer instanceof ISingleElectron) return contains((SingleElectron) electronContainer); return false; } /** * {@inheritDoc} */ @Override public String toString() { StringBuffer stringContent = new StringBuffer(64); stringContent.append("AtomContainer("); stringContent.append(this.hashCode()); if (getAtomCount() > 0) { stringContent.append(", #A:").append(getAtomCount()); for (int i = 0; i < getAtomCount(); i++) { stringContent.append(", ").append(getAtom(i).toString()); } } if (getBondCount() > 0) { stringContent.append(", #B:").append(getBondCount()); for (int i = 0; i < getBondCount(); i++) { stringContent.append(", ").append(getBond(i).toString()); } } if (getLonePairCount() > 0) { stringContent.append(", #LP:").append(getLonePairCount()); for (int i = 0; i < getLonePairCount(); i++) { stringContent.append(", ").append(getLonePair(i).toString()); } } if (getSingleElectronCount() > 0) { stringContent.append(", #SE:").append(getSingleElectronCount()); for (int i = 0; i < getSingleElectronCount(); i++) { stringContent.append(", ").append(getSingleElectron(i).toString()); } } if (stereoElements.size() > 0) { stringContent.append(", ST:[#").append(stereoElements.size()); for (IStereoElement elements : stereoElements) { stringContent.append(", ").append(elements.toString()); } stringContent.append(']'); } stringContent.append(')'); return stringContent.toString(); } /** * {@inheritDoc} */ @Override public IAtomContainer clone() throws CloneNotSupportedException { // this is pretty wasteful as we need to delete most the data // we can't simply create an empty instance as the sub classes (e.g. AminoAcid) // would have a ClassCastException when they invoke clone IAtomContainer clone = (IAtomContainer) super.clone(); // remove existing elements - we need to set the stereo elements list as list.clone() doesn't // work as expected and will also remove all elements from the original clone.setStereoElements(new ArrayList(stereoElements.size())); clone.removeAllElements(); // create a mapping of the original atoms/bonds to the cloned atoms/bonds // we need this mapping to correctly clone bonds, single/paired electrons // and stereo elements // - the expected size stop the map be resized - method from Google Guava Map atomMap = new HashMap(atomCount >= 3 ? atomCount + atomCount / 3 : atomCount + 1); Map bondMap = new HashMap(bondCount >= 3 ? bondCount + bondCount / 3 : bondCount + 1); // clone atoms IAtom[] atoms = new IAtom[this.atomCount]; for (int i = 0; i < atoms.length; i++) { atoms[i] = (IAtom) this.atoms[i].clone(); atomMap.put(this.atoms[i], atoms[i]); } clone.setAtoms(atoms); // clone bonds using a the mappings from the original to the clone IBond[] bonds = new IBond[this.bondCount]; for (int i = 0; i < bonds.length; i++) { IBond original = this.bonds[i]; IBond bond = (IBond) original.clone(); int n = bond.getAtomCount(); IAtom[] members = new IAtom[n]; for (int j = 0; j < n; j++) { members[j] = atomMap.get(original.getAtom(j)); } bond.setAtoms(members); bondMap.put(this.bonds[i], bond); bonds[i] = bond; } clone.setBonds(bonds); // clone lone pairs (we can't use an array to buffer as there is no setLonePairs()) for (int i = 0; i < lonePairCount; i++) { ILonePair original = this.lonePairs[i]; ILonePair pair = (ILonePair) original.clone(); if (pair.getAtom() != null) pair.setAtom(atomMap.get(original.getAtom())); clone.addLonePair(pair); } // clone single electrons (we can't use an array to buffer as there is no setSingleElectrons()) for (int i = 0; i < singleElectronCount; i++) { ISingleElectron original = this.singleElectrons[i]; ISingleElectron electron = (ISingleElectron) original.clone(); if (electron.getAtom() != null) electron.setAtom(atomMap.get(original.getAtom())); clone.addSingleElectron(electron); } // map each stereo element to a new instance in the clone for (IStereoElement element : stereoElements) { clone.addStereoElement(element.map(atomMap, bondMap)); } return clone; } /** * Generic grow function, expand an array by a varried amount to have * enough (required) space. * * @param array the array to expand * @param required the minimum required space * @param array type * @return the expanded array */ private static T[] grow(T[] array, int required) { int oldCapacity = array.length; // x1.5: 20, 30, 45, 67, 100, 150, 225, 337, 505, etc int newCapacity = oldCapacity == 0 ? DEFAULT_CAPACITY : oldCapacity + (oldCapacity >> 1); if (newCapacity < required) newCapacity = required; return Arrays.copyOf(array, newCapacity); } /** * Ensure there is enough space to accommodate the specified number of * atoms. * * @param required total number of atoms (inc. already used) */ private void ensureAtomCapacity(int required) { if (required > atoms.length) atoms = grow(atoms, required); } /** * Ensure there is enough space to accommodate the specified number of * bonds. * * @param required total number of bonds (inc. already used) */ private void ensureBondCapacity(int required) { if (required > bonds.length) bonds = grow(bonds, required); } /** * Ensure there is enough space to accommodate the specified number of * electrons. * * @param required total number of electrons (inc. already used) */ private void ensureElectronCapacity(int required) { if (required > singleElectrons.length) singleElectrons = grow(singleElectrons, required); } /** * Ensure there is enough space to accommodate the specified number of * lone pairs. * * @param required total number of lone pairs (inc. already used) */ private void ensureLonePairCapacity(int required) { if (required > lonePairs.length) lonePairs = grow(lonePairs, required); } /** * {@inheritDoc} */ @Override public void stateChanged(IChemObjectChangeEvent event) { notifyChanged(event); } /** * {@inheritDoc} */ @Override public boolean isEmpty() { return atomCount == 0; } /** * {@inheritDoc} */ @Override public String getTitle() { return getProperty(CDKConstants.TITLE); } /** * {@inheritDoc} */ @Override public void setTitle(String title) { setProperty(CDKConstants.TITLE, title); } /** * The inner AtomIterator class. */ private class AtomIterator implements Iterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < atomCount; } @Override public IAtom next() { return atoms[pointer++]; } @Override public void remove() { removeAtomOnly(--pointer); } } /** * The inner BondIterator class. */ private class BondIterator implements Iterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < bondCount; } @Override public IBond next() { return bonds[pointer++]; } @Override public void remove() { removeBond(--pointer); } } /** * The inner LonePairIterator class. */ private class LonePairIterator implements Iterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < lonePairCount; } @Override public ILonePair next() { return lonePairs[pointer++]; } @Override public void remove() { removeLonePair(--pointer); } } /** * The inner SingleElectronIterator class. */ private class SingleElectronIterator implements Iterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < singleElectronCount; } @Override public ISingleElectron next() { return singleElectrons[pointer++]; } @Override public void remove() { removeSingleElectron(--pointer); } } /** * The inner ElectronContainerIterator class. */ private class ElectronContainerIterator implements Iterator { private int pointer = 0; @Override public boolean hasNext() { return pointer < (bondCount + lonePairCount + singleElectronCount); } @Override public IElectronContainer next() { if (pointer < bondCount) return bonds[pointer++]; else if (pointer < bondCount + lonePairCount) return lonePairs[(pointer++) - bondCount]; else if (pointer < bondCount + lonePairCount + singleElectronCount) return singleElectrons[(pointer++) - bondCount - lonePairCount]; return null; } @Override public void remove() { if (pointer <= bondCount) removeBond(--pointer); else if (pointer <= bondCount + lonePairCount) removeLonePair((--pointer) - bondCount); else if (pointer <= bondCount + lonePairCount + singleElectronCount) removeSingleElectron((--pointer) - bondCount - lonePairCount); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy