Logo Search packages:      
Sourcecode: cdk version File versions  Download package

GeometryTools.java
/*  $Revision$ $Author$ $Date$
 *
 *  Copyright (C) 1997-2008  The Chemistry Development Kit (CDK) project
 *
 *  Contact: cdk-devel@lists.sourceforge.net
 *
 *  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.geometry;

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IRing;
import org.openscience.cdk.interfaces.IRingSet;
import org.openscience.cdk.tools.LoggingTool;

import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector2d;
import javax.vecmath.Vector3d;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * A set of static utility classes for geometric calculations and operations.
 * This class is extensively used, for example, by JChemPaint to edit molecule.
 * All methods in this class change the coordinates of the atoms. Use GeometryTools if you use an external set of coordinates (e. g. renderingCoordinates from RendererModel)
 *
 * @author        seb
 * @author        Stefan Kuhn
 * @author        Egon Willighagen
 * @author        Ludovic Petain
 * @author        Christian Hoppe
 * @author        Niels Out
 * 
 * @cdk.module    standard
 * @cdk.githash
 */
00059 public class GeometryTools {

      private static LoggingTool logger = new LoggingTool(GeometryTools.class);

      /**
       *  Adds an automatically calculated offset to the coordinates of all atoms
       *  such that all coordinates are positive and the smallest x or y coordinate
       *  is exactly zero.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  AtomContainer for which all the atoms are translated to
       *      positive coordinates
       */
00072       public static void translateAllPositive(IAtomContainer atomCon) {
            double minX = Double.MAX_VALUE;
            double
                        minY = Double.MAX_VALUE;
            Iterator<IAtom> atoms = atomCon.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom atom = (IAtom)atoms.next();
                  if (atom.getPoint2d() != null) {
                        if (atom.getPoint2d().x < minX) {
                              minX = atom.getPoint2d().x;
                        }
                        if (atom.getPoint2d().y < minY) {
                              minY = atom.getPoint2d().y;
                        }
                  }
            }
            logger.debug("Translating: minx=" + minX + ", minY=" + minY);
            translate2D(atomCon, minX * -1, minY * -1);
      }


      /**
       *  Translates the given molecule by the given Vector.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  The molecule to be translated
       *@param  transX   translation in x direction
       *@param  transY   translation in y direction
       */
00101       public static void translate2D(IAtomContainer atomCon, double transX, double transY) {
            translate2D(atomCon, new Vector2d(transX, transY));
      }


      /**
       *  Scales a molecule such that it fills a given percentage of a given
       *  dimension
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon     The molecule to be scaled
       *@param  areaDim     The dimension to be filled
       *@param  fillFactor  The percentage of the dimension to be filled
       */
00115       public static void scaleMolecule(IAtomContainer atomCon, Dimension areaDim, double fillFactor) {
            Dimension molDim = get2DDimension(atomCon);
            double widthFactor = (double) areaDim.width / (double) molDim.width;
            double heightFactor = (double) areaDim.height / (double) molDim.height;
            double scaleFactor = Math.min(widthFactor, heightFactor) * fillFactor;
            scaleMolecule(atomCon, scaleFactor);
      }


      /**
       *  Multiplies all the coordinates of the atoms of the given molecule with the
       *  scalefactor.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon      The molecule to be scaled
       *@param  scaleFactor  Description of the Parameter
       */
00132       public static void scaleMolecule(IAtomContainer atomCon, double scaleFactor) {
            for (int i = 0; i < atomCon.getAtomCount(); i++) {
                  if (atomCon.getAtom(i).getPoint2d() != null) {
                        atomCon.getAtom(i).getPoint2d().x *= scaleFactor;
                        atomCon.getAtom(i).getPoint2d().y *= scaleFactor;
                  }
            }
      }


      /**
       *  Centers the molecule in the given area
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  molecule to be centered
       *@param  areaDim  dimension in which the molecule is to be centered
       */
00149       public static void center(IAtomContainer atomCon, Dimension areaDim) {
            Dimension molDim = get2DDimension(atomCon);
            int transX = (areaDim.width - molDim.width) / 2;
            int transY = (areaDim.height - molDim.height) / 2;
            translateAllPositive(atomCon);
            translate2D(atomCon, new Vector2d(transX, transY));
      }


      /**
       *  Translates a molecule from the origin to a new point denoted by a vector.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  molecule to be translated
       *@param  vector   dimension that represents the translation vector
       */
00165       public static void translate2D(IAtomContainer atomCon, Vector2d vector) {
        for (IAtom atom : atomCon.atoms()) {
            if (atom.getPoint2d() != null) {
                atom.getPoint2d().add(vector);
            } else {
                logger.warn("Could not translate atom in 2D space");
            }
        }
      }


      /**
       *  Rotates a molecule around a given center by a given angle
       *
       *@param  atomCon  The molecule to be rotated
       *@param  center   A point giving the rotation center
       *@param  angle    The angle by which to rotate the molecule, in radians
       */
00183       public static void rotate(IAtomContainer atomCon, Point2d center, double angle) {
            Point2d point;
            double costheta = Math.cos(angle);
            double sintheta = Math.sin(angle);
            IAtom atom;
            for (int i = 0; i < atomCon.getAtomCount(); i++) {
                  atom = atomCon.getAtom(i);
                  point = atom.getPoint2d();
                  double relativex = point.x - center.x;
                  double relativey = point.y - center.y;
                  point.x = relativex * costheta - relativey * sintheta + center.x;
                  point.y = relativex * sintheta + relativey * costheta + center.y;
            }
      }

    /**
     * Rotates a 3D point about a specified line segment by a specified angle.
     *
     * The code is based on code available <a href="http://astronomy.swin.edu.au/~pbourke/geometry/rotate/source.c">here</a>.
     * Positive angles are anticlockwise looking down the axis towards the origin.
     * Assume right hand coordinate system.
     *
     * @param atom The atom to rotate
     * @param p1  The  first point of the line segment
     * @param p2  The second point of the line segment
     * @param angle  The angle to rotate by (in degrees)
     */
00210     public static void rotate(IAtom atom, Point3d p1, Point3d p2, double angle) {
        double costheta, sintheta;

        Point3d r = new Point3d();

        r.x = p2.x - p1.x;
        r.y = p2.y - p1.y;
        r.z = p2.z - p1.z;
        normalize(r);


        angle = angle * Math.PI / 180.0;
        costheta = Math.cos(angle);
        sintheta = Math.sin(angle);

        Point3d p = atom.getPoint3d();
        p.x -= p1.x;
        p.y -= p1.y;
        p.z -= p1.z;

        Point3d q = new Point3d(0, 0, 0);
        q.x += (costheta + (1 - costheta) * r.x * r.x) * p.x;
        q.x += ((1 - costheta) * r.x * r.y - r.z * sintheta) * p.y;
        q.x += ((1 - costheta) * r.x * r.z + r.y * sintheta) * p.z;

        q.y += ((1 - costheta) * r.x * r.y + r.z * sintheta) * p.x;
        q.y += (costheta + (1 - costheta) * r.y * r.y) * p.y;
        q.y += ((1 - costheta) * r.y * r.z - r.x * sintheta) * p.z;

        q.z += ((1 - costheta) * r.x * r.z - r.y * sintheta) * p.x;
        q.z += ((1 - costheta) * r.y * r.z + r.x * sintheta) * p.y;
        q.z += (costheta + (1 - costheta) * r.z * r.z) * p.z;

        q.x += p1.x;
        q.y += p1.y;
        q.z += p1.z;

        atom.setPoint3d(q);
    }

    /**
     * Normalizes a point.
     *
     * @param point The point to normalize
     */
00255     public static void normalize(Point3d point) {
        double sum = Math.sqrt(point.x * point.x + point.y * point.y + point.z * point.z);
        point.x = point.x / sum;
        point.y = point.y / sum;
        point.z = point.z / sum;
    }


      /**
       *  Returns the java.awt.Dimension of a molecule
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  of which the dimension should be returned
       *@return          The java.awt.Dimension of this molecule
       */
00270       public static Dimension get2DDimension(IAtomContainer atomCon) {
            double[] minmax = getMinMax(atomCon);
            double maxX = minmax[2];
            double
                        maxY = minmax[3];
            double
                        minX = minmax[0];
            double
                        minY = minmax[1];
            return new Dimension((int) (maxX - minX + 1), (int) (maxY - minY + 1));
      }


      /**
       *  Returns the minimum and maximum X and Y coordinates of the atoms in the
       *  AtomContainer. The output is returned as: <pre>
       *   minmax[0] = minX;
       *   minmax[1] = minY;
       *   minmax[2] = maxX;
       *   minmax[3] = maxY;
       * </pre>
       * See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@return            An four int array as defined above.
       */
00296       public static double[] getMinMax(IAtomContainer container) {
            double maxX = -Double.MAX_VALUE;
            double maxY = -Double.MAX_VALUE;
            double minX = Double.MAX_VALUE;
            double minY = Double.MAX_VALUE;
            for (int i = 0; i < container.getAtomCount(); i++) {
                  IAtom atom = container.getAtom(i);
                  if (atom.getPoint2d() != null) {
                        if (atom.getPoint2d().x > maxX) {
                              maxX = atom.getPoint2d().x;
                        }
                        if (atom.getPoint2d().x < minX) {
                              minX = atom.getPoint2d().x;
                        }
                        if (atom.getPoint2d().y > maxY) {
                              maxY = atom.getPoint2d().y;
                        }
                        if (atom.getPoint2d().y < minY) {
                              minY = atom.getPoint2d().y;
                        }
                  }
            }
            double[] minmax = new double[4];
            minmax[0] = minX;
            minmax[1] = minY;
            minmax[2] = maxX;
            minmax[3] = maxY;
            return minmax;
      }


      /**
       *  Translates a molecule from the origin to a new point denoted by a vector.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atomCon  molecule to be translated
       *@param  p        Description of the Parameter
       */
00334       public static void translate2DCentreOfMassTo(IAtomContainer atomCon, Point2d p) {
            Point2d com = get2DCentreOfMass(atomCon);
            Vector2d translation = new Vector2d(p.x - com.x, p.y - com.y);
            Iterator<IAtom> atoms = atomCon.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom atom = (IAtom)atoms.next();
                  if (atom.getPoint2d() != null) {
                        atom.getPoint2d().add(translation);
                  }
            }
      }


      /**
       *  Calculates the center of the given atoms and returns it as a Point2d
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atoms  The vector of the given atoms
       *@return        The center of the given atoms as Point2d
       */
00354       public static Point2d get2DCenter(Iterable<IAtom> atoms) {
            double xsum = 0;
            double ysum = 0;
            int length = 0;
            for (IAtom atom : atoms) {
                  if (atom.getPoint2d() != null) {
                        xsum += atom.getPoint2d().x;
                        ysum += atom.getPoint2d().y;
                        length++;
                  }
            }
            return new Point2d(xsum / (double) length, ysum / (double) length);
      }

      
      /**
       *  Calculates the center of the given atoms and returns it as a Point2d
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atoms  The Iterator of the given atoms
       *@return        The center of the given atoms as Point2d
       */
00376       public static Point2d get2DCenter(Iterator<IAtom> atoms) {
            IAtom atom;
            double xsum = 0;
            double ysum = 0;
            int length = 0;
            while (atoms.hasNext()) {
                  atom = (IAtom)atoms.next();
                  if (atom.getPoint2d() != null) {
                        xsum += atom.getPoint2d().x;
                        ysum += atom.getPoint2d().y;
                  }
                  ++length;
            }
            return new Point2d(xsum / (double) length, ysum / (double) length);
      }
      

      /**
       *  Returns the geometric center of all the rings in this ringset.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  ringSet  Description of the Parameter
       *@return          the geometric center of the rings in this ringset
       */
00400       public static Point2d get2DCenter(IRingSet ringSet) {
            double centerX = 0;
            double centerY = 0;
            for (int i = 0; i < ringSet.getAtomContainerCount(); i++) {
                  Point2d centerPoint = get2DCenter((IRing)ringSet.getAtomContainer(i));
                  centerX += centerPoint.x;
                  centerY += centerPoint.y;
            }
        return new Point2d(centerX / ((double) ringSet.getAtomContainerCount()), centerY / ((double) ringSet.getAtomContainerCount()));
      }


      /**
       *  Calculates the center of mass for the <code>Atom</code>s in the
       *  AtomContainer for the 2D coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  ac      AtomContainer for which the center of mass is calculated
       *@return         Null, if any of the atomcontainer {@link IAtom}'s masses are null
       *@cdk.keyword    center of mass
       */
00421       public static Point2d get2DCentreOfMass(IAtomContainer ac) {
            double xsum = 0.0;
            double ysum = 0.0;

            double totalmass = 0.0;

            Iterator<IAtom> atoms = ac.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom a = (IAtom) atoms.next();
                  Double mass = a.getExactMass();
                  if (mass == null) return null;
                  totalmass += mass;
                  xsum += mass * a.getPoint2d().x;
                  ysum += mass * a.getPoint2d().y;
            }

            return new Point2d(xsum / totalmass, ysum / totalmass);
      }


      /**
       *  Returns the geometric center of all the atoms in the atomContainer.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@return            the geometric center of the atoms in this atomContainer
       */
00448       public static Point2d get2DCenter(IAtomContainer container) {
            double centerX = 0;
            double centerY = 0;
            double counter = 0;
            Iterator<IAtom> atoms = container.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom atom = (IAtom)atoms.next();
                  if (atom.getPoint2d() != null) {
                        centerX += atom.getPoint2d().x;
                        centerY += atom.getPoint2d().y;
                        counter++;
                  }
            }
        return new Point2d(centerX / (counter), centerY / (counter));
      }

      
      /**
       *  Translates the geometric 2DCenter of the given
       *  AtomContainer container to the specified Point2d p.
       *
       *@param  container  AtomContainer which should be translated.
       *@param  p          New Location of the geometric 2D Center.
       *@see #get2DCenter
       *@see #translate2DCentreOfMassTo
       */
00474       public static void translate2DCenterTo(IAtomContainer container, Point2d p) {
            Point2d com = get2DCenter(container);
            Vector2d translation = new Vector2d(p.x - com.x, p.y - com.y);
            Iterator<IAtom> atoms = container.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom atom = (IAtom)atoms.next();
                  if (atom.getPoint2d() != null) {
                        atom.getPoint2d().add(translation);
                  }
            }
      }


      /**
       *  Calculates the center of mass for the <code>Atom</code>s in the
       *  AtomContainer for the 2D coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  ac      AtomContainer for which the center of mass is calculated
       *@return         Description of the Return Value
       *@cdk.keyword    center of mass
     * @cdk.dictref   blue-obelisk:calculate3DCenterOfMass
       */
00497       public static Point3d get3DCentreOfMass(IAtomContainer ac) {
            double xsum = 0.0;
            double ysum = 0.0;
            double zsum = 0.0;

            double totalmass = 0.0;

            Iterator<IAtom> atoms = ac.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom a = (IAtom)atoms.next();
                  Double mass = a.getExactMass();
                  // some sanity checking
                  if (a.getPoint3d() == null) return null;
                  if (mass == null) return null;

                  totalmass += mass;
                  xsum += mass * a.getPoint3d().x;
                  ysum += mass * a.getPoint3d().y;
                  zsum += mass * a.getPoint3d().z;
            }

            return new Point3d(xsum / totalmass, ysum / totalmass, zsum / totalmass);
      }


      /**
       *  Returns the geometric center of all the atoms in this atomContainer.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  ac  Description of the Parameter
       *@return     the geometric center of the atoms in this atomContainer
       */
00529       public static Point3d get3DCenter(IAtomContainer ac) {
            double centerX = 0;
            double centerY = 0;
            double centerZ = 0;
            double counter = 0;
            Iterator<IAtom> atoms = ac.atoms().iterator();
            while (atoms.hasNext()) {
                  IAtom atom = (IAtom)atoms.next();
                  if (atom.getPoint3d() != null) {
                        centerX += atom.getPoint3d().x;
                        centerY += atom.getPoint3d().y;
                        centerZ += atom.getPoint3d().z;
                        counter++;
                  }
            }
        return new Point3d(centerX / (counter), centerY / (counter), centerZ / (counter));
      }


      /**
       *  Gets the angle attribute of the GeometryTools class
       *
       *@param  xDiff  Description of the Parameter
       *@param  yDiff  Description of the Parameter
       *@return        The angle value
       */
00555       public static double getAngle(double xDiff, double yDiff) {
            double angle = 0;
//          logger.debug("getAngle->xDiff: " + xDiff);
//          logger.debug("getAngle->yDiff: " + yDiff);
            if (xDiff >= 0 && yDiff >= 0) {
                  angle = Math.atan(yDiff / xDiff);
            } else if (xDiff < 0 && yDiff >= 0) {
                  angle = Math.PI + Math.atan(yDiff / xDiff);
            } else if (xDiff < 0 && yDiff < 0) {
                  angle = Math.PI + Math.atan(yDiff / xDiff);
            } else if (xDiff >= 0 && yDiff < 0) {
                  angle = 2 * Math.PI + Math.atan(yDiff / xDiff);
            }
            return angle;
      }


      /**
       *  Gets the coordinates of two points (that represent a bond) and calculates
       *  for each the coordinates of two new points that have the given distance
       *  vertical to the bond.
       *
       *@param  coords  The coordinates of the two given points of the bond like this
       *      [point1x, point1y, point2x, point2y]
       *@param  dist    The vertical distance between the given points and those to
       *      be calculated
       *@return         The coordinates of the calculated four points
       */
00583       public static int[] distanceCalculator(int[] coords, double dist) {
            double angle;
            if ((coords[2] - coords[0]) == 0) {
                  angle = Math.PI / 2;
            } else {
                  angle = Math.atan(((double) coords[3] - (double) coords[1]) / ((double) coords[2] - (double) coords[0]));
            }
            int begin1X = (int) (Math.cos(angle + Math.PI / 2) * dist + coords[0]);
            int begin1Y = (int) (Math.sin(angle + Math.PI / 2) * dist + coords[1]);
            int begin2X = (int) (Math.cos(angle - Math.PI / 2) * dist + coords[0]);
            int begin2Y = (int) (Math.sin(angle - Math.PI / 2) * dist + coords[1]);
            int end1X = (int) (Math.cos(angle - Math.PI / 2) * dist + coords[2]);
            int end1Y = (int) (Math.sin(angle - Math.PI / 2) * dist + coords[3]);
            int end2X = (int) (Math.cos(angle + Math.PI / 2) * dist + coords[2]);
            int end2Y = (int) (Math.sin(angle + Math.PI / 2) * dist + coords[3]);

        return new int[]{begin1X, begin1Y, begin2X, begin2Y, end1X, end1Y, end2X, end2Y};
      }
      
      public static double[] distanceCalculator(double[] coords, double dist) {
            double angle;
            if ((coords[2] - coords[0]) == 0) {
                  angle = Math.PI / 2;
            } else {
                  angle = Math.atan(((double) coords[3] - (double) coords[1]) / ((double) coords[2] - (double) coords[0]));
            }
            double begin1X = (Math.cos(angle + Math.PI / 2) * dist + coords[0]);
            double begin1Y = (Math.sin(angle + Math.PI / 2) * dist + coords[1]);
            double begin2X = (Math.cos(angle - Math.PI / 2) * dist + coords[0]);
            double begin2Y = (Math.sin(angle - Math.PI / 2) * dist + coords[1]);
            double end1X = (Math.cos(angle - Math.PI / 2) * dist + coords[2]);
            double end1Y = (Math.sin(angle - Math.PI / 2) * dist + coords[3]);
            double end2X = (Math.cos(angle + Math.PI / 2) * dist + coords[2]);
            double end2Y = (Math.sin(angle + Math.PI / 2) * dist + coords[3]);

        return new double[]{begin1X, begin1Y, begin2X, begin2Y, end1X, end1Y, end2X, end2Y};
      }

      /**
       *  Writes the coordinates of the atoms participating the given bond into an
       *  array.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  bond  The given bond
       *@return       The array with the coordinates
       */
00629       public static int[] getBondCoordinates(IBond bond) {
            if (bond.getAtom(0).getPoint2d() == null ||
                        bond.getAtom(1).getPoint2d() == null) {
                  logger.error("getBondCoordinates() called on Bond without 2D coordinates!");
                  return new int[0];
            }
            int beginX = (int) bond.getAtom(0).getPoint2d().x;
            int endX = (int) bond.getAtom(1).getPoint2d().x;
            int beginY = (int) bond.getAtom(0).getPoint2d().y;
            int endY = (int) bond.getAtom(1).getPoint2d().y;
        return new int[]{beginX, beginY, endX, endY};
      }


      /**
       *  Returns the atom of the given molecule that is closest to the given
       *  coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  xPosition  The x coordinate
       *@param  yPosition  The y coordinate
       *@param  atomCon    The molecule that is searched for the closest atom
       *@return            The atom that is closest to the given coordinates
       */
00653       public static IAtom getClosestAtom(int xPosition, int yPosition, IAtomContainer atomCon) {
            IAtom closestAtom = null;
            IAtom currentAtom;
            double smallestMouseDistance = -1;
            double mouseDistance;
            double atomX;
            double atomY;
            for (int i = 0; i < atomCon.getAtomCount(); i++) {
                  currentAtom = atomCon.getAtom(i);
                  atomX = currentAtom.getPoint2d().x;
                  atomY = currentAtom.getPoint2d().y;
                  mouseDistance = Math.sqrt(Math.pow(atomX - xPosition, 2) + Math.pow(atomY - yPosition, 2));
                  if (mouseDistance < smallestMouseDistance || smallestMouseDistance == -1) {
                        smallestMouseDistance = mouseDistance;
                        closestAtom = currentAtom;
                  }
            }
            return closestAtom;
      }
      /**
       *  Returns the atom of the given molecule that is closest to the given
       *  coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  xPosition  The x coordinate
       *@param  yPosition  The y coordinate
       *@param  atomCon    The molecule that is searched for the closest atom
       *@return            The atom that is closest to the given coordinates
       */
00682       public static IAtom getClosestAtom(double xPosition, double yPosition, IAtomContainer atomCon) {
            IAtom closestAtom = null;
            IAtom currentAtom;
            double smallestMouseDistance = -1;
            double mouseDistance;
            double atomX;
            double atomY;
            for (int i = 0; i < atomCon.getAtomCount(); i++) {
                  currentAtom = atomCon.getAtom(i);
                  atomX = currentAtom.getPoint2d().x;
                  atomY = currentAtom.getPoint2d().y;
                  mouseDistance = Math.sqrt(Math.pow(atomX - xPosition, 2) + Math.pow(atomY - yPosition, 2));
                  if (mouseDistance < smallestMouseDistance || smallestMouseDistance == -1) {
                        smallestMouseDistance = mouseDistance;
                        closestAtom = currentAtom;
                  }
            }
            return closestAtom;
      }

      /**
       *  Returns the bond of the given molecule that is closest to the given
       *  coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  xPosition  The x coordinate
       *@param  yPosition  The y coordinate
       *@param  atomCon    The molecule that is searched for the closest bond
       *@return            The bond that is closest to the given coordinates
       */
00712       public static IBond getClosestBond(int xPosition, int yPosition, IAtomContainer atomCon) {
            Point2d bondCenter;
            IBond closestBond = null;

            double smallestMouseDistance = -1;
            double mouseDistance;
        Iterator<IBond> bonds = atomCon.bonds().iterator();
        while (bonds.hasNext()) {
            IBond currentBond =  (IBond) bonds.next();
                  bondCenter = get2DCenter(currentBond.atoms());
                  mouseDistance = Math.sqrt(Math.pow(bondCenter.x - xPosition, 2) + Math.pow(bondCenter.y - yPosition, 2));
                  if (mouseDistance < smallestMouseDistance || smallestMouseDistance == -1) {
                        smallestMouseDistance = mouseDistance;
                        closestBond = currentBond;
                  }
            }
            return closestBond;
      }
      /**
       *  Returns the bond of the given molecule that is closest to the given
       *  coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  xPosition  The x coordinate
       *@param  yPosition  The y coordinate
       *@param  atomCon    The molecule that is searched for the closest bond
       *@return            The bond that is closest to the given coordinates
       */
00740       public static IBond getClosestBond(double xPosition, double yPosition, IAtomContainer atomCon) {
            Point2d bondCenter;
            IBond closestBond = null;

            double smallestMouseDistance = -1;
            double mouseDistance;
        Iterator<IBond> bonds = atomCon.bonds().iterator();
        while (bonds.hasNext()) {
            IBond currentBond =  (IBond) bonds.next();
                  bondCenter = get2DCenter(currentBond.atoms());
                  mouseDistance = Math.sqrt(Math.pow(bondCenter.x - xPosition, 2) + Math.pow(bondCenter.y - yPosition, 2));
                  if (mouseDistance < smallestMouseDistance || smallestMouseDistance == -1) {
                        smallestMouseDistance = mouseDistance;
                        closestBond = currentBond;
                  }
            }
            return closestBond;
      }

      /**
       *  Sorts a Vector of atoms such that the 2D distances of the atom locations
       *  from a given point are smallest for the first atoms in the vector
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  point  The point from which the distances to the atoms are measured
       *@param  atoms  The atoms for which the distances to point are measured
       */
00767       public static void sortBy2DDistance(IAtom[] atoms, Point2d point) {
            double distance1;
            double distance2;
            IAtom atom1;
            IAtom atom2;
            boolean doneSomething;
            do {
                  doneSomething = false;
                  for (int f = 0; f < atoms.length - 1; f++) {
                        atom1 = atoms[f];
                        atom2 = atoms[f + 1];
                        distance1 = point.distance(atom1.getPoint2d());
                        distance2 = point.distance(atom2.getPoint2d());
                        if (distance2 < distance1) {
                              atoms[f] = atom2;
                              atoms[f + 1] = atom1;
                              doneSomething = true;
                        }
                  }
            } while (doneSomething);
      }


      /**
       *  Determines the scale factor for displaying a structure loaded from disk in
       *  a frame. An average of all bond length values is produced and a scale
       *  factor is determined which would scale the given molecule such that its
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container          The AtomContainer for which the ScaleFactor is to be
       *      calculated
       *@param  bondLength  The target bond length
       *@return             The ScaleFactor with which the AtomContainer must be
       *      scaled to have the target bond length
       */

00803       public static double getScaleFactor(IAtomContainer container, double bondLength) {
            double currentAverageBondLength = getBondLengthAverage(container);
    if(currentAverageBondLength==0 || Double.isNaN(currentAverageBondLength))
      return 1;
            return bondLength / currentAverageBondLength;
      }


      /**
       *  An average of all 2D bond length values is produced. Bonds which have
       *  Atom's with no coordinates are disregarded.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  The AtomContainer for which the average bond length is to be
       *      calculated
       *@return     the average bond length
       */
00820       public static double getBondLengthAverage(IAtomContainer container) {
            double bondLengthSum = 0;
        Iterator<IBond> bonds = container.bonds().iterator();
        int bondCounter = 0;
        while (bonds.hasNext()) {
            IBond bond = bonds.next();
                  IAtom atom1 = bond.getAtom(0);
                  IAtom atom2 = bond.getAtom(1);
                  if (atom1.getPoint2d() != null &&
                              atom2.getPoint2d() != null) {
                        bondCounter++;
                        bondLengthSum += getLength2D(bond);
                  }
            }
            return bondLengthSum / bondCounter;
      }


      /**
       *  Returns the geometric length of this bond in 2D space.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  bond  Description of the Parameter
       *@return       The geometric length of this bond
       */
00845       public static double getLength2D(IBond bond) {
            if (bond.getAtom(0) == null ||
                        bond.getAtom(1) == null) {
                  return 0.0;
            }
            Point2d point1 = bond.getAtom(0).getPoint2d();
            Point2d point2 = bond.getAtom(1).getPoint2d();
            if (point1 == null || point2 == null) {
                  return 0.0;
            }
            return point1.distance(point2);
      }


      /**
       *  Determines if this AtomContainer contains 2D coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@return    boolean indication that 2D coordinates are available
       */
00866       public static boolean has2DCoordinates(IAtomContainer container) {
            return has2DCoordinatesNew(container)>0;
      }


      /**
       *  Determines if this AtomContainer contains 2D coordinates for some or all molecules.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *
       *@param container the molecule to be considered
     * @return    0 no 2d, 1=some, 2= for each atom
       */
00879       public static int has2DCoordinatesNew(IAtomContainer container) {
            if (container == null) return 0;
            
            boolean no2d=false;
            boolean with2d=false;
        for (IAtom atom : container.atoms()) {
            if (atom.getPoint2d() == null) {
                no2d = true;
            } else {
                with2d = true;
            }
        }
            if(!no2d && with2d){
                  return 2;
            } else if(no2d && with2d){
                  return 1;
            } else{
                  return 0;
            }
      }


      /**
       *  Determines if this Atom contains 2D coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  atom  Description of the Parameter
       *@return    boolean indication that 2D coordinates are available
       */
00908       public static boolean has2DCoordinates(IAtom atom) {
            return (atom.getPoint2d() != null);
      }


      /**
       *  Determines if this Bond contains 2D coordinates.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  bond  Description of the Parameter
       *@return    boolean indication that 2D coordinates are available
       */
00920       public static boolean has2DCoordinates(IBond bond) {
        for (IAtom iAtom : bond.atoms()) {
            if (iAtom.getPoint2d() == null) {
                return false;
            }
        }
            return true;
      }


      /**
       *  Determines if this model contains 3D coordinates
       *
       *@param container the molecule to consider
       *@return    boolean indication that 3D coordinates are available
       */
00936       public static boolean has3DCoordinates(IAtomContainer container) {
            boolean hasinfo = true;
        for (IAtom atom : container.atoms()) {
            if (atom.getPoint3d() == null) {
                return false;
            }
        }
            return hasinfo;
      }


      /**
       *  Determines the normalized vector orthogonal on the vector p1->p2.
       *
       *@param  point1  Description of the Parameter
       *@param  point2  Description of the Parameter
       *@return     Description of the Return Value
       */
00954       public static Vector2d calculatePerpendicularUnitVector(Point2d point1, Point2d point2) {
            Vector2d vector = new Vector2d();
            vector.sub(point2, point1);
            vector.normalize();

            // Return the perpendicular vector
            return new Vector2d(-1.0 * vector.y, vector.x);
      }


      /**
       *  Calculates the normalization factor in order to get an average bond length
       *  of 1.5. It takes only into account Bond's with two atoms.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@return            The normalizationFactor value
       */
00972       public static double getNormalizationFactor(IAtomContainer container) {
            double bondlength = 0.0;
            double ratio;
            /*
             *  Desired bond length for storing structures in MDL mol files
             *  This should probably be set externally (from system wide settings)
             */
            double desiredBondLength = 1.5;
            // loop over all bonds and determine the mean bond distance
            int counter = 0;
        for (IBond bond : container.bonds()) {
            // only consider two atom bonds into account
            if (bond.getAtomCount() == 2) {
                counter++;
                IAtom atom1 = bond.getAtom(0);
                IAtom atom2 = bond.getAtom(1);
                bondlength += Math.sqrt(Math.pow(atom1.getPoint2d().x - atom2.getPoint2d().x, 2) +
                        Math.pow(atom1.getPoint2d().y - atom2.getPoint2d().y, 2));
            }
        }
            bondlength = bondlength / counter;
            ratio = desiredBondLength / bondlength;
            return ratio;
      }


      /**
       *  Determines the best alignment for the label of an atom in 2D space. It
       *  returns 1 if left aligned, and -1 if right aligned.
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@param  atom       Description of the Parameter
       *@return            The bestAlignmentForLabel value
       */
01007       public static int getBestAlignmentForLabel(IAtomContainer container, IAtom atom) {
            double overallDiffX = 0;
            for (IAtom connectedAtom : container.getConnectedAtomsList(atom)) {
                  overallDiffX += connectedAtom.getPoint2d().x - atom.getPoint2d().x;
            }
            if (overallDiffX <= 0) {
                  return 1;
            } else {
                  return -1;
            }
      }

      /**
       *  Determines the best alignment for the label of an atom in 2D space. It
       *  returns 1 if right (=default) aligned, and -1 if left aligned.
       *  returns 2 if top aligned, and -2 if H is aligned below the atom
       *  See comment for center(IAtomContainer atomCon, Dimension areaDim, HashMap renderingCoordinates) for details on coordinate sets
       *
       *@param  container  Description of the Parameter
       *@param  atom       Description of the Parameter
       *@return            The bestAlignmentForLabel value
       */
01029       public static int getBestAlignmentForLabelXY(IAtomContainer container, IAtom atom) {
            double overallDiffX = 0;
            double overallDiffY = 0;
            for (IAtom connectedAtom : container.getConnectedAtomsList(atom)) {
                  overallDiffX += connectedAtom.getPoint2d().x - atom.getPoint2d().x;
                  overallDiffY += connectedAtom.getPoint2d().y - atom.getPoint2d().y;
            }
            if (overallDiffX <= 0) {
                  if (overallDiffX < overallDiffY)
                        return 1;//right aligned
                  else
                        return 2;//top aligned.
            } else {
                  if (overallDiffX > overallDiffY)
                        return -1;//left aligned
                  else
                        return -2;//H below aligned
            }
      }


      /**
       *  Returns the atoms which are closes to an atom in an AtomContainer by
       *  distance in 3d.
       *
       *@param  container         The AtomContainer to examine
       *@param  startAtom         the atom to start from
       *@param  max               the number of neighbours to return
       *@return                   the average bond length
       *@exception  CDKException  Description of the Exception
       */
01060       public static List<IAtom> findClosestInSpace(IAtomContainer container, IAtom startAtom, int max) throws CDKException {
            Point3d originalPoint = startAtom.getPoint3d();
            if (originalPoint == null) {
                  throw new CDKException("No point3d, but findClosestInSpace is working on point3ds");
            }
            Map<Double,IAtom> atomsByDistance = new TreeMap<Double,IAtom>();
            for (IAtom atom : container.atoms()) {
                  if (atom != startAtom) {
                        if (atom.getPoint3d() == null) {
                              throw new CDKException("No point3d, but findClosestInSpace is working on point3ds");
                        }
                        double distance = atom.getPoint3d().distance(originalPoint);
                        atomsByDistance.put(distance, atom);
                  }
            }
            // FIXME: should there not be some sort here??
            Set<Double> keySet = atomsByDistance.keySet();
            Iterator<Double> keyIter = keySet.iterator();
            List<IAtom> returnValue = new ArrayList<IAtom>();
            int i = 0;
            while (keyIter.hasNext() && i < max) {
                  returnValue.add(atomsByDistance.get(keyIter.next()));
                  i++;
            }
            return (returnValue);
      }
      /**
       *  Returns a Map with the AtomNumbers, the first number corresponds to the first (or the largest
       *  AtomContainer) atomcontainer. It is recommend to sort the atomContainer due to their number of atoms before
       *  calling this function.
       *  
       *  The molecules needs to be aligned before! (coordinates are needed)
       *
       *@param  firstAtomContainer                the (largest) first aligned AtomContainer which is the reference
       *@param  secondAtomContainer               the second aligned AtomContainer
       *@param  searchRadius                          the radius of space search from each atom
       *@return                                       a Map of the mapped atoms
       *@exception  CDKException  Description of the Exception
       */
01099       public static Map<Integer,Integer> mapAtomsOfAlignedStructures(IAtomContainer firstAtomContainer, IAtomContainer secondAtomContainer, 
                  double searchRadius, Map<Integer,Integer> mappedAtoms)throws CDKException {
            //to return the mapping setProperty("MappedAtom",AtomNumber)
            //logger.debug("**** MAP ATOMS ****");
            getLargestAtomContainer(firstAtomContainer,secondAtomContainer);
            double[][] distanceMatrix=new double[firstAtomContainer.getAtomCount()][secondAtomContainer.getAtomCount()];
            for (int i=0;i<firstAtomContainer.getAtomCount();i++){
                  Point3d firstAtomPoint=firstAtomContainer.getAtom(i).getPoint3d();
                  //logger.debug("Closest atoms of "+firstAtomContainer.getAtoms()[i].getSymbol()+" :");
                  for (int j=0;j<secondAtomContainer.getAtomCount();j++){
                        distanceMatrix[i][j]=firstAtomPoint.distance(secondAtomContainer.getAtom(j).getPoint3d());
                        //logger.debug("Distance "+i+" "+j+":"+distanceMatrix[i][j]);
                  }
                  //logger.debug(" Atoms from the secondAtomContainer");
            }
            
            //logger.debug();
            //logger.debug("\t");
            //for (int j=0;j<secondAtomContainer.getAtomCount();j++){
                  //logger.debug(j+" "+secondAtomContainer.getAtomAt(j).getSymbol()+"\t");
            //}
            //DEBUGG
            /*double tmp=0;
            for(int i=0;i<firstAtomContainer.getAtomCount();i++){
                  //logger.debug(i+" "+firstAtomContainer.getAtomAt(i).getSymbol()+"\t");
                  for (int j=0;j<secondAtomContainer.getAtomCount();j++){
                        tmp=Math.floor(distanceMatrix[i][j]*10);
                        //logger.debug(tmp/10+"\t");
                  }                 
            }*/
            
            double minimumDistance;
        for(int i=0;i<firstAtomContainer.getAtomCount();i++){
            minimumDistance=searchRadius;
            for (int j=0;j<secondAtomContainer.getAtomCount();j++){
                if(distanceMatrix[i][j]< searchRadius && distanceMatrix[i][j]< minimumDistance){
                    //logger.debug("Distance OK "+i+" "+j+":"+distanceMatrix[i][j]+" AtomCheck:"+checkAtomMapping(firstAtomContainer,secondAtomContainer, i, j));
                    //check atom properties
                    if (checkAtomMapping(firstAtomContainer,secondAtomContainer, i, j)){
                        minimumDistance=distanceMatrix[i][j];
                        mappedAtoms.put(
                              firstAtomContainer.getAtomNumber(firstAtomContainer.getAtom(i)),
                              secondAtomContainer.getAtomNumber(secondAtomContainer.getAtom(j))
                        );
                        //firstAtomContainer.getAtomAt(i).setProperty("MappedAtom",new Integer(secondAtomContainer.getAtomNumber(secondAtomContainer.getAtomAt(j))));
                        //logger.debug("#:"+countMappedAtoms+" Atom:"+i+" is mapped to Atom"+j);
                        //logger.debug(firstAtomContainer.getConnectedAtoms(firstAtomContainer.getAtomAt(i)).length);
                    }
                }
            }
        }
            return mappedAtoms;
      }

      // FIXME: huh!?!?!
    private static void getLargestAtomContainer(IAtomContainer firstAC, IAtomContainer secondAC) {
        if (firstAC.getAtomCount() < secondAC.getAtomCount()){
            IAtomContainer tmp;
            try {
                tmp = (IAtomContainer) firstAC.clone();
                firstAC=(IAtomContainer)secondAC.clone();
                secondAC=(IAtomContainer)tmp.clone();
            } catch (CloneNotSupportedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
      
      private static boolean checkAtomMapping(IAtomContainer firstAC, IAtomContainer secondAC, int posFirstAtom, int posSecondAtom){
            IAtom firstAtom=firstAC.getAtom(posFirstAtom);
            IAtom secondAtom=secondAC.getAtom(posSecondAtom);
            if (firstAtom.getSymbol().equals(secondAtom.getSymbol()) && firstAC.getConnectedAtomsList(firstAtom).size() == secondAC.getConnectedAtomsList(secondAtom).size() &&
                        firstAtom.getBondOrderSum() == secondAtom.getBondOrderSum() &&
                        firstAtom.getMaxBondOrder() == secondAtom.getMaxBondOrder() 
                    ){
                  return true;
            }else {
                  return false;
            }
      }
      
      private static IAtomContainer setVisitedFlagsToFalse(IAtomContainer atomContainer) {
        for (int i=0;i<atomContainer.getAtomCount();i++){
            atomContainer.getAtom(i).setFlag(CDKConstants.VISITED, false);
        }
        return atomContainer;
    }
      
      /**
       *  Return the RMSD of bonds length between the 2 aligned molecules.
       *
       *@param  firstAtomContainer                the (largest) first aligned AtomContainer which is the reference
       *@param  secondAtomContainer               the second aligned AtomContainer
       *@param  mappedAtoms                           Map: a Map of the mapped atoms
       *@param  Coords3d                                  boolean: true if moecules has 3D coords, false if molecules has 2D coords
       *@return                                       double: all the RMSD of bonds length
       *
       **/
01198       public static double getBondLengthRMSD(IAtomContainer firstAtomContainer, IAtomContainer secondAtomContainer,
                  Map<Integer,Integer> mappedAtoms, boolean Coords3d) {
        //logger.debug("**** GT getBondLengthRMSD ****");
        Iterator<Integer> firstAtoms=mappedAtoms.keySet().iterator();
        IAtom centerAtomFirstMolecule;
        IAtom centerAtomSecondMolecule;
        List<IAtom> connectedAtoms;
        double sum=0;
        double n=0;
        double distance1=0;
        double distance2=0;
        setVisitedFlagsToFalse(firstAtomContainer);
        setVisitedFlagsToFalse(secondAtomContainer);
        while(firstAtoms.hasNext()){
            centerAtomFirstMolecule=firstAtomContainer.getAtom(firstAtoms.next());
            centerAtomFirstMolecule.setFlag(CDKConstants.VISITED, true);
            centerAtomSecondMolecule=secondAtomContainer.getAtom(mappedAtoms.get(firstAtomContainer.getAtomNumber(centerAtomFirstMolecule)));
            connectedAtoms=firstAtomContainer.getConnectedAtomsList(centerAtomFirstMolecule);
            for (int i=0;i<connectedAtoms.size();i++){
                  IAtom conAtom = (IAtom)connectedAtoms.get(i);
                //this step is built to know if the program has already calculate a bond length (so as not to have duplicate values)
                if(!conAtom.getFlag(CDKConstants.VISITED)){
                    if (Coords3d){
                        distance1=((Point3d)centerAtomFirstMolecule.getPoint3d()).distance(conAtom.getPoint3d());
                        distance2=((Point3d)centerAtomSecondMolecule.getPoint3d()).distance(secondAtomContainer.getAtom(mappedAtoms.get(firstAtomContainer.getAtomNumber(conAtom))).getPoint3d());
                        sum=sum+Math.pow((distance1-distance2),2);
                        n++;
                    }else{
                        distance1=((Point2d)centerAtomFirstMolecule.getPoint2d()).distance(conAtom.getPoint2d());
                        distance2=((Point2d)centerAtomSecondMolecule.getPoint2d()).distance(secondAtomContainer.getAtom((mappedAtoms.get(firstAtomContainer.getAtomNumber(conAtom)))).getPoint2d());
                        sum=sum+Math.pow((distance1-distance2),2);
                        n++;
                    }
                }
            }
        }
        setVisitedFlagsToFalse(firstAtomContainer);
        setVisitedFlagsToFalse(secondAtomContainer);
        return Math.sqrt(sum/n);
    }
      /**
       *  Return the variation of each angle value between the 2 aligned molecules.
       *
       *@param  firstAtomContainer                the (largest) first aligned AtomContainer which is the reference
       *@param  secondAtomContainer               the second aligned AtomContainer
       *@param  mappedAtoms                           Map: a Map of the mapped atoms
       *@return                                       double: the value of the RMSD
       *
       **/
01247       public static double getAngleRMSD(IAtomContainer firstAtomContainer, IAtomContainer secondAtomContainer, Map<Integer,Integer> mappedAtoms) {
        //logger.debug("**** GT getAngleRMSD ****");
        Iterator<Integer> firstAtoms=mappedAtoms.keySet().iterator();
        //logger.debug("mappedAtoms:"+mappedAtoms.toString());
        IAtom firstAtomfirstAC;
        IAtom centerAtomfirstAC;
        IAtom firstAtomsecondAC;
        IAtom secondAtomsecondAC;
        IAtom centerAtomsecondAC;
        double angleFirstMolecule;
        double angleSecondMolecule;
        double sum=0;
        double n=0;
        while(firstAtoms.hasNext()){
            int firstAtomNumber= firstAtoms.next();
            centerAtomfirstAC=firstAtomContainer.getAtom(firstAtomNumber);
            List<IAtom> connectedAtoms=firstAtomContainer.getConnectedAtomsList(centerAtomfirstAC);
            if (connectedAtoms.size() >1){
                //logger.debug("If "+centerAtomfirstAC.getSymbol()+" is the center atom :");
                for (int i=0; i < connectedAtoms.size()-1;i++){
                    firstAtomfirstAC=(IAtom)connectedAtoms.get(i);
                    for (int j=i+1; j < connectedAtoms.size();j++){
                        angleFirstMolecule=getAngle(centerAtomfirstAC,firstAtomfirstAC,(IAtom)connectedAtoms.get(j));
                        centerAtomsecondAC=secondAtomContainer.getAtom(mappedAtoms.get(firstAtomContainer.getAtomNumber(centerAtomfirstAC)));
                        firstAtomsecondAC=secondAtomContainer.getAtom(mappedAtoms.get(firstAtomContainer.getAtomNumber(firstAtomfirstAC)));
                        secondAtomsecondAC=secondAtomContainer.getAtom(mappedAtoms.get(firstAtomContainer.getAtomNumber((IAtom)connectedAtoms.get(j))));
                        angleSecondMolecule=getAngle(centerAtomsecondAC,firstAtomsecondAC,secondAtomsecondAC);
                        sum=sum+Math.pow(angleFirstMolecule-angleSecondMolecule,2);
                        n++;
                        //logger.debug("Error for the "+firstAtomfirstAC.getSymbol().toLowerCase()+"-"+centerAtomfirstAC.getSymbol()+"-"+connectedAtoms[j].getSymbol().toLowerCase()+" Angle :"+deltaAngle+" degrees");
                    }
                }
            }//if
        }
        return Math.sqrt(sum/n);
    }
      
      private static double getAngle(IAtom atom1, IAtom atom2, IAtom atom3){
            
            Vector3d centerAtom = new Vector3d();
            centerAtom.x=atom1.getPoint3d().x;
            centerAtom.y=atom1.getPoint3d().y;
            centerAtom.z=atom1.getPoint3d().z;
            Vector3d firstAtom = new Vector3d();
            Vector3d secondAtom = new Vector3d();
                  
            firstAtom.x=atom2.getPoint3d().x;
            firstAtom.y=atom2.getPoint3d().y;
            firstAtom.z=atom2.getPoint3d().z;
                        
            secondAtom.x=atom3.getPoint3d().x;
            secondAtom.y=atom3.getPoint3d().y;
            secondAtom.z=atom3.getPoint3d().z;
                        
            firstAtom.sub(centerAtom);
            secondAtom.sub(centerAtom);
                        
            return firstAtom.angle(secondAtom);
      }
      
      /**
       *  Return the RMSD between the 2 aligned molecules.
       *
       *@param  firstAtomContainer                the (largest) first aligned AtomContainer which is the reference
       *@param  secondAtomContainer               the second aligned AtomContainer
       *@param  mappedAtoms                           Map: a Map of the mapped atoms
       *@param  Coords3d                                  boolean: true if molecules has 3D coords, false if molecules has 2D coords
       *@return                                       double: the value of the RMSD 
       *@exception  CDKException  if there is an error in getting mapped atoms
       *
       **/
01318       public static double getAllAtomRMSD(IAtomContainer firstAtomContainer, IAtomContainer secondAtomContainer, 
                Map<Integer,Integer> mappedAtoms, boolean Coords3d)throws CDKException {
            //logger.debug("**** GT getAllAtomRMSD ****");
            double sum=0;
            double RMSD;
            Iterator<Integer> firstAtoms=mappedAtoms.keySet().iterator();
            int firstAtomNumber;
            int secondAtomNumber;
            int n=0;
            while(firstAtoms.hasNext()){
                  firstAtomNumber= firstAtoms.next();
                  try{
                        secondAtomNumber= mappedAtoms.get(firstAtomNumber);
                        IAtom firstAtom=firstAtomContainer.getAtom(firstAtomNumber);
                        if (Coords3d){
                              sum=sum+Math.pow(firstAtom.getPoint3d().distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint3d()),2);
                              n++;
                        }else{
                              sum=sum+Math.pow(firstAtom.getPoint2d().distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint2d()),2);
                              n++;
                        }
                  }catch (Exception ex){
                throw new CDKException(ex.getMessage(), ex);
            }
            }
            RMSD=Math.sqrt(sum/n);
            return RMSD;
      }
      
      /**
       *  Return the RMSD of the heavy atoms between the 2 aligned molecules.
       *
       *@param  firstAtomContainer                the (largest) first aligned AtomContainer which is the reference
       *@param  secondAtomContainer               the second aligned AtomContainer
       *@param  mappedAtoms                           Map: a Map of the mapped atoms
       *@param hetAtomOnly                        boolean: true if only hetero atoms should be considered
       *@param  Coords3d                                  boolean: true if molecules has 3D coords, false if molecules has 2D coords
       *@return                                       double: the value of the RMSD 
       *
       **/
01358       public static double getHeavyAtomRMSD(IAtomContainer firstAtomContainer, IAtomContainer secondAtomContainer,
                  Map<Integer,Integer> mappedAtoms, boolean hetAtomOnly ,boolean Coords3d) {
            //logger.debug("**** GT getAllAtomRMSD ****");
            double sum=0;
            double RMSD=0;
            Iterator<Integer> firstAtoms=mappedAtoms.keySet().iterator();
            int firstAtomNumber=0;
            int secondAtomNumber=0;
            int n=0;
            while(firstAtoms.hasNext()){
                  firstAtomNumber=firstAtoms.next();
                        secondAtomNumber=mappedAtoms.get(firstAtomNumber);
                        IAtom firstAtom=firstAtomContainer.getAtom(firstAtomNumber);
                        if (hetAtomOnly){
                              if (!firstAtom.getSymbol().equals("H") && !firstAtom.getSymbol().equals("C")){
                                    if (Coords3d){
                                          sum=sum+Math.pow(((Point3d)firstAtom.getPoint3d()).distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint3d()),2);
                                          n++;
                                    }else{
                                          sum=sum+Math.pow(((Point2d)firstAtom.getPoint2d()).distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint2d()),2);
                                          n++;
                                    }
                              }
                        }else{
                              if (!firstAtom.getSymbol().equals("H")){
                                    if (Coords3d){
                                          sum=sum+Math.pow(((Point3d)firstAtom.getPoint3d()).distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint3d()),2);
                                          n++;
                                    }else{
                                          sum=sum+Math.pow(((Point2d)firstAtom.getPoint2d()).distance(secondAtomContainer.getAtom(secondAtomNumber).getPoint2d()),2);
                                          n++;
                                    }
                              }
                        }

            }
            RMSD=Math.sqrt(sum/n);
            return RMSD;
      }



      /**
       *  An average of all 3D bond length values is produced, using point3ds in atoms.
       *  Atom's with no coordinates are disregarded.
       *
       *@param  container  The AtomContainer for which the average bond length is to be
       *      calculated
       *@return     the average bond length
       */
01408       public static double getBondLengthAverage3D(IAtomContainer container) {
            double bondLengthSum = 0;
        int bondCounter = 0;
        for (IBond bond : container.bonds()) {
            IAtom atom1 = bond.getAtom(0);
            IAtom atom2 = bond.getAtom(1);
            if (atom1.getPoint3d() != null &&
                    atom2.getPoint3d() != null) {
                bondCounter++;
                bondLengthSum += atom1.getPoint3d().distance(atom2.getPoint3d());
            }
        }
            return bondLengthSum / bondCounter;
      }
}

Generated by  Doxygen 1.6.0   Back to index