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

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

/* Copyright (C) 2000-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.
 * All we ask is that proper credit is given for our work, which includes
 * - but is not limited to - adding the above copyright notice to the beginning
 * of your source code files, and to any copyright notice that you may distribute
 * with programs based on this work.
 *
 * 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 org.openscience.cdk.config.Elements;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IElement;

import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import java.io.Serializable;
import java.util.Objects;

/**
 * Represents the idea of an chemical atom.
 *
 * 

An Atom class is instantiated with at least the atom symbol: *

 *   Atom a = new Atom("C");
 * 
* *

Once instantiated all field not filled by passing parameters * to the constructor are null. Atoms can be configured by using * the IsotopeFactory.configure() method: *

 *   IsotopeFactory if = IsotopeFactory.getInstance(a.getNewBuilder());
 *   if.configure(a);
 * 
* *

More examples about using this class can be found in the * Junit test for this class. * * @cdk.module data * @cdk.githash * * @author steinbeck * @cdk.created 2000-10-02 * @cdk.keyword atom * * @see org.openscience.cdk.config.XMLIsotopeFactory#getInstance(org.openscience.cdk.interfaces.IChemObjectBuilder) */ public class Atom extends AtomType implements IAtom, Serializable, Cloneable { /* * Let's keep this exact specification of what kind of point2d we're talking * of here, since there are so many around in the java standard api */ /** * 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 = -3137373012494608794L; /** * A 2D point specifying the location of this atom in a 2D coordinate * space. */ protected Point2d point2d = (Point2d) CDKConstants.UNSET; /** * A 3 point specifying the location of this atom in a 3D coordinate * space. */ protected Point3d point3d = (Point3d) CDKConstants.UNSET; /** * A 3 point specifying the location of this atom in a crystal unit cell. */ protected Point3d fractionalPoint3d = (Point3d) CDKConstants.UNSET; /** * The number of implicitly bound hydrogen atoms for this atom. */ protected Integer hydrogenCount = (Integer) CDKConstants.UNSET; /** * A stereo parity descriptor for the stereochemistry of this atom. */ protected Integer stereoParity = (Integer) CDKConstants.UNSET; /** * The partial charge of the atom. * * The default value is {@link CDKConstants#UNSET} and serves to provide a check whether the charge has been * set or not */ protected Double charge = (Double) CDKConstants.UNSET; /** * Constructs an completely unset Atom. */ public Atom() { super((String) null); } /** * Create a new atom with of the specified element. * * @param elem atomic number */ public Atom(int elem) { this(elem, 0, 0); } /** * Create a new atom with of the specified element and hydrogen count. * * @param elem atomic number * @param hcnt hydrogen count */ public Atom(int elem, int hcnt) { this(elem, hcnt, 0); } /** * Create a new atom with of the specified element, hydrogen count, and formal charge. * * @param elem atomic number * @param hcnt hydrogen count * @param fchg formal charge */ public Atom(int elem, int hcnt, int fchg) { super((String)null); setAtomicNumber(elem); setSymbol(Elements.ofNumber(elem).symbol()); setImplicitHydrogenCount(hcnt); setFormalCharge(fchg); } /** * Constructs an Atom from a string containing an element symbol and optionally * the atomic mass, hydrogen count, and formal charge. The symbol grammar allows * easy construction from common symbols, for example: * *

     *     new Atom("NH+");   // nitrogen cation with one hydrogen
     *     new Atom("OH");    // hydroxy
     *     new Atom("O-");    // oxygen anion
     *     new Atom("13CH3"); // methyl isotope 13
     * 
* *
     *     atom := {mass}? {symbol} {hcnt}? {fchg}?
     *     mass := \d+
     *     hcnt := 'H' \d+
     *     fchg := '+' \d+? | '-' \d+?
     * 
* * @param symbol string with the element symbol */ public Atom(String symbol) { super((String)null); if (!parseAtomSymbol(this, symbol)) throw new IllegalArgumentException("Cannot pass atom symbol: " + symbol); } /** * Constructs an Atom from an Element and a Point3d. * * @param elementSymbol The symbol of the atom * @param point3d The 3D coordinates of the atom */ public Atom(String elementSymbol, Point3d point3d) { this(elementSymbol); this.point3d = point3d; } /** * Constructs an Atom from an Element and a Point2d. * * @param elementSymbol The Element * @param point2d The Point */ public Atom(String elementSymbol, Point2d point2d) { this(elementSymbol); this.point2d = point2d; } /** * Constructs an isotope by copying the symbol, atomic number, * flags, identifier, exact mass, natural abundance, mass * number, maximum bond order, bond order sum, van der Waals * and covalent radii, formal charge, hybridization, electron * valency, formal neighbour count and atom type name from the * given IAtomType. It does not copy the listeners and * properties. If the element is an instance of * IAtom, then the 2D, 3D and fractional coordinates, partial * atomic charge, hydrogen count and stereo parity are copied * too. * * @param element IAtomType to copy information from */ public Atom(IElement element) { super(element); if (element instanceof IAtom) { if (((IAtom) element).getPoint2d() != null) { this.point2d = new Point2d(((IAtom) element).getPoint2d()); } else { this.point2d = null; } if (((IAtom) element).getPoint3d() != null) { this.point3d = new Point3d(((IAtom) element).getPoint3d()); } else { this.point3d = null; } if (((IAtom) element).getFractionalPoint3d() != null) { this.fractionalPoint3d = new Point3d(((IAtom) element).getFractionalPoint3d()); } else { this.fractionalPoint3d = null; } this.hydrogenCount = ((IAtom) element).getImplicitHydrogenCount(); this.charge = ((IAtom) element).getCharge(); this.stereoParity = ((IAtom) element).getStereoParity(); } } /** * {@inheritDoc} */ @Override public IAtomContainer getContainer() { return null; } /** * {@inheritDoc} */ @Override public int getIndex() { return -1; } /** * {@inheritDoc} */ @Override public Iterable bonds() { throw new UnsupportedOperationException(); } /** * {@inheritDoc} */ @Override public int getBondCount() { throw new UnsupportedOperationException(); } /** * Sets the partial charge of this atom. * * @param charge The partial charge * * @see #getCharge */ @Override public void setCharge(Double charge) { this.charge = charge; notifyChanged(); } /** * Returns the partial charge of this atom. * * If the charge has not been set the return value is Double.NaN * * @return the charge of this atom * * @see #setCharge */ @Override public Double getCharge() { return this.charge; } /** * Sets the number of implicit hydrogen count of this atom. * * @param hydrogenCount The number of hydrogen atoms bonded to this atom. * * @see #getImplicitHydrogenCount */ @Override public void setImplicitHydrogenCount(Integer hydrogenCount) { this.hydrogenCount = hydrogenCount; notifyChanged(); } /** * Returns the hydrogen count of this atom. * * @return The hydrogen count of this atom. * * @see #setImplicitHydrogenCount */ @Override public Integer getImplicitHydrogenCount() { return this.hydrogenCount; } /** * * Sets a point specifying the location of this * atom in a 2D space. * * @param point2d A point in a 2D plane * * @see #getPoint2d */ @Override public void setPoint2d(Point2d point2d) { this.point2d = point2d; notifyChanged(); } /** * * Sets a point specifying the location of this * atom in 3D space. * * @param point3d A point in a 3-dimensional space * * @see #getPoint3d */ @Override public void setPoint3d(Point3d point3d) { this.point3d = point3d; notifyChanged(); } /** * Sets a point specifying the location of this * atom in a Crystal unit cell. * * @param point3d A point in a 3d fractional unit cell space * * @see #getFractionalPoint3d * @see org.openscience.cdk.Crystal */ @Override public void setFractionalPoint3d(Point3d point3d) { this.fractionalPoint3d = point3d; notifyChanged(); } /** * Sets the stereo parity for this atom. * * @param stereoParity The stereo parity for this atom * * @see org.openscience.cdk.CDKConstants for predefined values. * @see #getStereoParity */ @Override public void setStereoParity(Integer stereoParity) { this.stereoParity = stereoParity; notifyChanged(); } /** * Returns a point specifying the location of this * atom in a 2D space. * * @return A point in a 2D plane. Null if unset. * * @see #setPoint2d */ @Override public Point2d getPoint2d() { return this.point2d; } /** * Returns a point specifying the location of this * atom in a 3D space. * * @return A point in 3-dimensional space. Null if unset. * * @see #setPoint3d */ @Override public Point3d getPoint3d() { return this.point3d; } /** * Returns a point specifying the location of this * atom in a Crystal unit cell. * * @return A point in 3d fractional unit cell space. Null if unset. * * @see #setFractionalPoint3d * @see org.openscience.cdk.CDKConstants for predefined values. */ @Override public Point3d getFractionalPoint3d() { return this.fractionalPoint3d; } /** * Returns the stereo parity of this atom. It uses the predefined values * found in CDKConstants. * * @return The stereo parity for this atom * * @see org.openscience.cdk.CDKConstants * @see #setStereoParity */ @Override public Integer getStereoParity() { return this.stereoParity; } /** * Compares a atom with this atom. * * @param object of type Atom * @return true, if the atoms are equal */ @Override public boolean compare(Object object) { if (!(object instanceof IAtom)) { return false; } if (!super.compare(object)) { return false; } Atom atom = (Atom) object; // XXX: floating point comparision! if (((point2d == atom.point2d) || ((point2d != null) && (point2d.equals(atom.point2d)))) && ((point3d == atom.point3d) || ((point3d != null) && (point3d.equals(atom.point3d)))) && (Objects.equals(hydrogenCount, atom.hydrogenCount)) && (Objects.equals(stereoParity, atom.stereoParity)) && (Objects.equals(charge, atom.charge))) { return true; } return false; } /** {@inheritDoc} */ @Override public boolean isAromatic() { return getFlag(CDKConstants.ISAROMATIC); } /** {@inheritDoc} */ @Override public void setIsAromatic(boolean arom) { setFlag(CDKConstants.ISAROMATIC, arom); } /** {@inheritDoc} */ @Override public boolean isInRing() { return getFlag(CDKConstants.ISINRING); } /** {@inheritDoc} */ @Override public void setIsInRing(boolean ring) { setFlag(CDKConstants.ISINRING, ring); } /** * Returns a one line string representation of this Atom. * Methods is conform RFC #9. * * @return The string representation of this Atom */ @Override public String toString() { StringBuffer stringContent = new StringBuffer(64); stringContent.append("Atom(").append(hashCode()); if (getSymbol() != null) { stringContent.append(", S:").append(getSymbol()); } if (getImplicitHydrogenCount() != null) { stringContent.append(", H:").append(getImplicitHydrogenCount()); } if (getStereoParity() != null) { stringContent.append(", SP:").append(getStereoParity()); } if (getPoint2d() != null) { stringContent.append(", 2D:[").append(getPoint2d()).append(']'); } if (getPoint3d() != null) { stringContent.append(", 3D:[").append(getPoint3d()).append(']'); } if (getFractionalPoint3d() != null) { stringContent.append(", F3D:[").append(getFractionalPoint3d()); } if (getCharge() != null) { stringContent.append(", C:").append(getCharge()); } stringContent.append(", ").append(super.toString()); stringContent.append(')'); return stringContent.toString(); } /** * Clones this atom object and its content. * * @return The cloned object */ @Override public IAtom clone() throws CloneNotSupportedException { Object clone = super.clone(); if (point2d != null) { ((Atom) clone).setPoint2d(new Point2d(point2d.x, point2d.y)); } if (point3d != null) { ((Atom) clone).setPoint3d(new Point3d(point3d.x, point3d.y, point3d.z)); } if (fractionalPoint3d != null) { ((Atom) clone).setFractionalPoint3d(new Point3d(fractionalPoint3d.x, fractionalPoint3d.y, fractionalPoint3d.z)); } return (IAtom) clone; } private static boolean isUpper(char c) { return c >= 'A' && c <= 'Z'; } private static boolean isLower(char c) { return c >= 'a' && c <= 'z'; } private static boolean isDigit(char c) { return c >= '0' && c <= '9'; } private static boolean parseAtomSymbol(IAtom atom, String str) { final int len = str.length(); int pos = 0; int mass = -1; int anum = 0; int hcnt = 0; int chg = 0; // optional mass if (pos < len && isDigit(str.charAt(pos))) { mass = (str.charAt(pos++) - '0'); while (pos < len && isDigit(str.charAt(pos))) mass = 10 * mass + (str.charAt(pos++) - '0'); } else if ("R".equals(str)) { atom.setAtomicNumber(0); atom.setSymbol("R"); return true; } else if ("*".equals(str)) { atom.setAtomicNumber(0); atom.setSymbol("*"); return true; } else if ("D".equals(str)) { atom.setAtomicNumber(1); atom.setMassNumber(2); atom.setSymbol("H"); return true; } else if ("T".equals(str)) { atom.setAtomicNumber(1); atom.setMassNumber(3); atom.setSymbol("H"); return true; } // atom symbol if (pos < len && isUpper(str.charAt(pos))) { int beg = pos; pos++; while (pos < len && isLower(str.charAt(pos))) pos++; Elements elem = Elements.ofString(str.substring(beg, pos)); if (elem == Elements.Unknown) return false; anum = elem.number(); // optional fields after atom symbol while (pos < len) { switch (str.charAt(pos)) { case 'H': pos++; if (pos < len && isDigit(str.charAt(pos))) { while (pos < len && isDigit(str.charAt(pos))) hcnt = 10 * hcnt + (str.charAt(pos++) - '0'); } else { hcnt = 1; } break; case '+': pos++; if (pos < len && isDigit(str.charAt(pos))) { chg = (str.charAt(pos++) - '0'); while (pos < len && isDigit(str.charAt(pos))) chg = 10 * chg + (str.charAt(pos++) - '0'); } else { chg = +1; } break; case '-': pos++; if (pos < len && isDigit(str.charAt(pos))) { chg = (str.charAt(pos++) - '0'); while (pos < len && isDigit(str.charAt(pos))) chg = 10 * chg + (str.charAt(pos++) - '0'); chg *= -1; } else { chg = -1; } break; default: return false; } } } else { return false; } if (mass < 0) atom.setMassNumber(null); else atom.setMassNumber(mass); atom.setAtomicNumber(anum); atom.setSymbol(Elements.ofNumber(anum).symbol()); atom.setImplicitHydrogenCount(hcnt); atom.setFormalCharge(chg); return pos == len && len > 0; } /** * {@inheritDoc} */ @Override public int hashCode() { return super.hashCode(); } /** * {@inheritDoc} */ @Override public boolean equals(Object obj) { if (obj instanceof AtomRef) return super.equals(((AtomRef) obj).deref()); return super.equals(obj); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy