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

org.biojava.nbio.structure.Calc Maven / Gradle / Ivy

There is a newer version: 7.2.2
Show newest version
/*
 *                    BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 * Created on 08.05.2004
 *
 */
package org.biojava.nbio.structure ;

import org.biojava.nbio.structure.jama.Matrix;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.vecmath.Matrix3d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

/**
 * Utility operations on Atoms, AminoAcids, etc.
 * 

* Currently the coordinates of an Atom are stored as an array * of size 3 (double[3]). It would be more powerful to use Point3D from * javax.vecmath, but unfortunately this is not a part of standard * java installations, since it comes with java3d. So to keep things * simple at the moment biojava does not depend on java3d. * * @author Andreas Prlic * @since 1.4 * @version %I% %G% */ public class Calc { private final static Logger logger = LoggerFactory.getLogger(Calc.class); /** * calculate distance between two atoms. * * @param a an Atom object * @param b an Atom object * @return a double */ public static final double getDistance(Atom a, Atom b) { double x = a.getX() - b.getX(); double y = a.getY() - b.getY(); double z = a.getZ() - b.getZ(); double s = x * x + y * y + z * z; return Math.sqrt(s); } /** * Will calculate the square of distances between two atoms. This will be * faster as it will not perform the final square root to get the actual * distance. Use this if doing large numbers of distance comparisons - it is * marginally faster than getDistance(). * * @param a an Atom object * @param b an Atom object * @return a double */ public static double getDistanceFast(Atom a, Atom b) { double x = a.getX() - b.getX(); double y = a.getY() - b.getY(); double z = a.getZ() - b.getZ(); return x * x + y * y + z * z; } public static final Atom invert(Atom a) { double[] coords = new double[]{0.0,0.0,0.0} ; Atom zero = new AtomImpl(); zero.setCoords(coords); return subtract(zero, a); } /** add two atoms ( a + b). * * @param a an Atom object * @param b an Atom object * @return an Atom object */ public static final Atom add(Atom a, Atom b){ Atom c = new AtomImpl(); c.setX( a.getX() + b.getX() ); c.setY( a.getY() + b.getY() ); c.setZ( a.getZ() + b.getZ() ); return c ; } /** subtract two atoms ( a - b). * * @param a an Atom object * @param b an Atom object * @return n new Atom object representing the difference */ public static final Atom subtract(Atom a, Atom b) { Atom c = new AtomImpl(); c.setX( a.getX() - b.getX() ); c.setY( a.getY() - b.getY() ); c.setZ( a.getZ() - b.getZ() ); return c ; } /** Vector product (cross product). * * @param a an Atom object * @param b an Atom object * @return an Atom object */ public static final Atom vectorProduct(Atom a , Atom b){ Atom c = new AtomImpl(); c.setX( a.getY() * b.getZ() - a.getZ() * b.getY() ) ; c.setY( a.getZ() * b.getX() - a.getX() * b.getZ() ) ; c.setZ( a.getX() * b.getY() - a.getY() * b.getX() ) ; return c ; } /** * Scalar product (dot product). * * @param a an Atom object * @param b an Atom object * @return a double */ public static final double scalarProduct(Atom a, Atom b) { return a.getX() * b.getX() + a.getY() * b.getY() + a.getZ() * b.getZ(); } /** * Gets the length of the vector (2-norm) * * @param a an Atom object * @return Square root of the sum of the squared elements */ public static final double amount(Atom a){ return Math.sqrt(scalarProduct(a,a)); } /** * Gets the angle between two vectors * * @param a an Atom object * @param b an Atom object * @return Angle between a and b in degrees, in range [0,180]. * If either vector has length 0 then angle is not defined and NaN is returned */ public static final double angle(Atom a, Atom b){ Vector3d va = new Vector3d(a.getCoords()); Vector3d vb = new Vector3d(b.getCoords()); return Math.toDegrees(va.angle(vb)); } /** * Returns the unit vector of vector a . * * @param a an Atom object * @return an Atom object */ public static final Atom unitVector(Atom a) { double amount = amount(a) ; double[] coords = new double[3]; coords[0] = a.getX() / amount ; coords[1] = a.getY() / amount ; coords[2] = a.getZ() / amount ; a.setCoords(coords); return a; } /** * Calculate the torsion angle, i.e. the angle between the normal vectors of the * two plains a-b-c and b-c-d. * See http://en.wikipedia.org/wiki/Dihedral_angle * @param a an Atom object * @param b an Atom object * @param c an Atom object * @param d an Atom object * @return the torsion angle in degrees, in range +-[0,180]. * If either first 3 or last 3 atoms are colinear then torsion angle is not defined and NaN is returned */ public static final double torsionAngle(Atom a, Atom b, Atom c, Atom d) { Atom ab = subtract(a,b); Atom cb = subtract(c,b); Atom bc = subtract(b,c); Atom dc = subtract(d,c); Atom abc = vectorProduct(ab,cb); Atom bcd = vectorProduct(bc,dc); double angl = angle(abc,bcd) ; /* calc the sign: */ Atom vecprod = vectorProduct(abc,bcd); double val = scalarProduct(cb,vecprod); if (val<0.0) angl = -angl ; return angl; } /** * Calculate the phi angle. * * @param a an AminoAcid object * @param b an AminoAcid object * @return a double * @throws StructureException if aminoacids not connected or if any of the 4 needed atoms missing */ public static final double getPhi(AminoAcid a, AminoAcid b) throws StructureException { if ( ! isConnected(a,b)){ throw new StructureException("can not calc Phi - AminoAcids are not connected!") ; } Atom a_C = a.getC(); Atom b_N = b.getN(); Atom b_CA = b.getCA(); Atom b_C = b.getC(); // C and N were checked in isConnected already if (b_CA==null) throw new StructureException("Can not calculate Phi, CA atom is missing"); return torsionAngle(a_C,b_N,b_CA,b_C); } /** * Calculate the psi angle. * * @param a an AminoAcid object * @param b an AminoAcid object * @return a double * @throws StructureException if aminoacids not connected or if any of the 4 needed atoms missing */ public static final double getPsi(AminoAcid a, AminoAcid b) throws StructureException { if ( ! isConnected(a,b)) { throw new StructureException("can not calc Psi - AminoAcids are not connected!") ; } Atom a_N = a.getN(); Atom a_CA = a.getCA(); Atom a_C = a.getC(); Atom b_N = b.getN(); // C and N were checked in isConnected already if (a_CA==null) throw new StructureException("Can not calculate Psi, CA atom is missing"); return torsionAngle(a_N,a_CA,a_C,b_N); } /** * Test if two amino acids are connected, i.e. * if the distance from C to N < 2.5 Angstrom. * * If one of the AminoAcids has an atom missing, returns false. * * @param a an AminoAcid object * @param b an AminoAcid object * @return true if ... */ public static final boolean isConnected(AminoAcid a, AminoAcid b) { Atom C = null ; Atom N = null; C = a.getC(); N = b.getN(); if ( C == null || N == null) return false; // one could also check if the CA atoms are < 4 A... double distance = getDistance(C,N); return distance < 2.5; } /** * Rotate a single Atom aroud a rotation matrix. * The rotation Matrix must be a pre-multiplication 3x3 Matrix. * * If the matrix is indexed m[row][col], then the matrix will be * pre-multiplied (y=atom*M) * @param atom atom to be rotated * @param m a rotation matrix represented as a double[3][3] array */ public static final void rotate(Atom atom, double[][] m){ double x = atom.getX(); double y = atom.getY() ; double z = atom.getZ(); double nx = m[0][0] * x + m[0][1] * y + m[0][2] * z ; double ny = m[1][0] * x + m[1][1] * y + m[1][2] * z ; double nz = m[2][0] * x + m[2][1] * y + m[2][2] * z ; atom.setX(nx); atom.setY(ny); atom.setZ(nz); } /** * Rotate a structure. * The rotation Matrix must be a pre-multiplication Matrix. * * @param structure a Structure object * @param rotationmatrix an array (3x3) of double * representing the rotation matrix. * @throws StructureException ... */ public static final void rotate(Structure structure, double[][] rotationmatrix) throws StructureException { if ( rotationmatrix.length != 3 ) { throw new StructureException ("matrix does not have size 3x3 !"); } AtomIterator iter = new AtomIterator(structure) ; while (iter.hasNext()) { Atom atom = iter.next() ; Calc.rotate(atom,rotationmatrix); } } /** * Rotate a Group. * The rotation Matrix must be a pre-multiplication Matrix. * * @param group a group object * @param rotationmatrix an array (3x3) of double * representing the rotation matrix. * @throws StructureException ... */ public static final void rotate(Group group, double[][] rotationmatrix) throws StructureException { if ( rotationmatrix.length != 3 ) { throw new StructureException ("matrix does not have size 3x3 !"); } AtomIterator iter = new AtomIterator(group) ; while (iter.hasNext()) { Atom atom = null ; atom = iter.next() ; rotate(atom,rotationmatrix); } } /** * Rotate an Atom around a Matrix object. * The rotation Matrix must be a pre-multiplication Matrix. * * @param atom atom to be rotated * @param m rotation matrix to be applied to the atom */ public static final void rotate(Atom atom, Matrix m){ double x = atom.getX(); double y = atom.getY(); double z = atom.getZ(); double[][] ad = new double[][]{{x,y,z}}; Matrix am = new Matrix(ad); Matrix na = am.times(m); atom.setX(na.get(0,0)); atom.setY(na.get(0,1)); atom.setZ(na.get(0,2)); } /** * Rotate a group object. * The rotation Matrix must be a pre-multiplication Matrix. * * @param group a group to be rotated * @param m a Matrix object representing the rotation matrix */ public static final void rotate(Group group, Matrix m){ AtomIterator iter = new AtomIterator(group) ; while (iter.hasNext()) { Atom atom = iter.next() ; rotate(atom,m); } } /** * Rotate a structure object. * The rotation Matrix must be a pre-multiplication Matrix. * * @param structure the structure to be rotated * @param m rotation matrix to be applied */ public static final void rotate(Structure structure, Matrix m){ AtomIterator iter = new AtomIterator(structure) ; while (iter.hasNext()) { Atom atom = iter.next() ; rotate(atom,m); } } /** * Transform an array of atoms at once. * The transformation Matrix must be a post-multiplication Matrix. * * @param ca array of Atoms to shift * @param t transformation Matrix4d */ public static void transform(Atom[] ca, Matrix4d t) { for (Atom atom : ca) Calc.transform(atom, t); } /** * Transforms an atom object, given a Matrix4d (i.e. the vecmath library * double-precision 4x4 rotation+translation matrix). * The transformation Matrix must be a post-multiplication Matrix. * * @param atom * @param m */ public static final void transform (Atom atom, Matrix4d m) { Point3d p = new Point3d(atom.getX(),atom.getY(),atom.getZ()); m.transform(p); atom.setX(p.x); atom.setY(p.y); atom.setZ(p.z); } /** * Transforms a group object, given a Matrix4d (i.e. the vecmath library * double-precision 4x4 rotation+translation matrix). * The transformation Matrix must be a post-multiplication Matrix. * * @param group * @param m */ public static final void transform (Group group, Matrix4d m) { AtomIterator iter = new AtomIterator(group) ; while (iter.hasNext()) { Atom atom = iter.next() ; transform(atom,m); } } /** * Transforms a structure object, given a Matrix4d (i.e. the vecmath library * double-precision 4x4 rotation+translation matrix). * The transformation Matrix must be a post-multiplication Matrix. * * @param structure * @param m */ public static final void transform (Structure structure, Matrix4d m) { AtomIterator iter = new AtomIterator(structure) ; while (iter.hasNext()) { Atom atom = iter.next() ; transform(atom,m); } } /** * Transforms a chain object, given a Matrix4d (i.e. the vecmath library * double-precision 4x4 rotation+translation matrix). * The transformation Matrix must be a post-multiplication Matrix. * * @param chain * @param m */ public static final void transform (Chain chain, Matrix4d m) { for (Group g:chain.getAtomGroups()) { for (Atom atom: g.getAtoms()) { transform(atom,m); } } } /** * Translates an atom object, given a Vector3d (i.e. the vecmath library * double-precision 3-d vector) * @param atom * @param v */ public static final void translate (Atom atom, Vector3d v) { atom.setX(atom.getX()+v.x); atom.setY(atom.getY()+v.y); atom.setZ(atom.getZ()+v.z); } /** * Translates a group object, given a Vector3d (i.e. the vecmath library * double-precision 3-d vector) * @param group * @param v */ public static final void translate (Group group, Vector3d v) { AtomIterator iter = new AtomIterator(group) ; while (iter.hasNext()) { Atom atom = iter.next() ; translate(atom,v); } } /** * Translates a chain object, given a Vector3d (i.e. the vecmath library * double-precision 3-d vector) * @param chain * @param v */ public static final void translate (Chain chain, Vector3d v) { for (Group g:chain.getAtomGroups()) { for (Atom atom: g.getAtoms()) { translate(atom,v); } } } /** * Translates a Structure object, given a Vector3d (i.e. the vecmath library * double-precision 3-d vector) * @param structure * @param v */ public static final void translate (Structure structure, Vector3d v) { AtomIterator iter = new AtomIterator(structure) ; while (iter.hasNext()) { Atom atom = iter.next() ; translate(atom,v); } } /** calculate structure + Matrix coodinates ... * * @param s the structure to operate on * @param matrix a Matrix object */ public static final void plus(Structure s, Matrix matrix){ AtomIterator iter = new AtomIterator(s) ; Atom oldAtom = null; Atom rotOldAtom = null; while (iter.hasNext()) { Atom atom = null ; atom = iter.next() ; try { if ( oldAtom != null){ logger.debug("before {}", getDistance(oldAtom,atom)); } } catch (Exception e){ logger.error("Exception: ", e); } oldAtom = (Atom)atom.clone(); double x = atom.getX(); double y = atom.getY() ; double z = atom.getZ(); double[][] ad = new double[][]{{x,y,z}}; Matrix am = new Matrix(ad); Matrix na = am.plus(matrix); double[] coords = new double[3] ; coords[0] = na.get(0,0); coords[1] = na.get(0,1); coords[2] = na.get(0,2); atom.setCoords(coords); try { if ( rotOldAtom != null){ logger.debug("after {}", getDistance(rotOldAtom,atom)); } } catch (Exception e){ logger.error("Exception: ", e); } rotOldAtom = (Atom) atom.clone(); } } /** shift a structure with a vector. * * @param structure a Structure object * @param a an Atom object representing a shift vector */ public static final void shift(Structure structure, Atom a ){ AtomIterator iter = new AtomIterator(structure) ; while (iter.hasNext() ) { Atom atom = null ; atom = iter.next() ; Atom natom = add(atom,a); double x = natom.getX(); double y = natom.getY() ; double z = natom.getZ(); atom.setX(x); atom.setY(y); atom.setZ(z); } } /** Shift a vector. * * @param a vector a * @param b vector b */ public static final void shift(Atom a, Atom b){ Atom natom = add(a,b); double x = natom.getX(); double y = natom.getY() ; double z = natom.getZ(); a.setX(x); a.setY(y); a.setZ(z); } /** Shift a Group with a vector. * * @param group a group object * @param a an Atom object representing a shift vector */ public static final void shift(Group group , Atom a ){ AtomIterator iter = new AtomIterator(group) ; while (iter.hasNext() ) { Atom atom = null ; atom = iter.next() ; Atom natom = add(atom,a); double x = natom.getX(); double y = natom.getY() ; double z = natom.getZ(); atom.setX(x); atom.setY(y); atom.setZ(z); } } /** Returns the center of mass of the set of atoms. * @param atomSet a set of Atoms * @return an Atom representing the Centroid of the set of atoms */ public static final Atom getCentroid(Atom[] atomSet){ double[] coords = new double[3]; coords[0] = 0; coords[1] = 0; coords[2] = 0 ; for (Atom a : atomSet) { coords[0] += a.getX(); coords[1] += a.getY(); coords[2] += a.getZ(); } int n = atomSet.length; coords[0] = coords[0] / n; coords[1] = coords[1] / n; coords[2] = coords[2] / n; Atom vec = new AtomImpl(); vec.setCoords(coords); return vec; } public static Atom centerOfMass(Atom[] points) { Atom center = new AtomImpl(); float totalMass = 0.0f; for (Atom a : points) { float mass = a.getElement().getAtomicMass(); totalMass += mass; center = scaleAdd(mass, a, center); } center = scaleEquals(center, 1.0f/totalMass); return center; } /** * Multiply elements of a by s (in place) * @param a * @param s * @return the modified a */ public static Atom scaleEquals(Atom a, double s) { double x = a.getX(); double y = a.getY(); double z = a.getZ(); x *= s; y *= s; z *= s; //Atom b = new AtomImpl(); a.setX(x); a.setY(y); a.setZ(z); return a; } /** * Multiply elements of a by s * @param a * @param s * @return A new Atom with s*a */ public static Atom scale(Atom a, double s) { double x = a.getX(); double y = a.getY(); double z = a.getZ(); Atom b = new AtomImpl(); b.setX(x*s); b.setY(y*s); b.setZ(z*s); return b; } /** * Perform linear transformation s*X+B, and store the result in b * @param s Amount to scale x * @param x Input coordinate * @param b Vector to translate (will be modified) * @return b, after modification */ public static Atom scaleAdd(double s, Atom x, Atom b){ double xc = s*x.getX() + b.getX(); double yc = s*x.getY() + b.getY(); double zc = s*x.getZ() + b.getZ(); //Atom a = new AtomImpl(); b.setX(xc); b.setY(yc); b.setZ(zc); return b; } /** Returns the Vector that needs to be applied to shift a set of atoms * to the Centroid. * @param atomSet array of Atoms * @return the vector needed to shift the set of atoms to its geometric center */ public static final Atom getCenterVector(Atom[] atomSet){ Atom centroid = getCentroid(atomSet); return getCenterVector(atomSet,centroid); } /** Returns the Vector that needs to be applied to shift a set of atoms * to the Centroid, if the centroid is already known * @param atomSet array of Atoms * @return the vector needed to shift the set of atoms to its geometric center */ public static final Atom getCenterVector(Atom[] atomSet, Atom centroid){ double[] coords = new double[3]; coords[0] = 0 - centroid.getX(); coords[1] = 0 - centroid.getY(); coords[2] = 0 - centroid.getZ(); Atom shiftVec = new AtomImpl(); shiftVec.setCoords(coords); return shiftVec; } /** Center the atoms at the Centroid. * @param atomSet a set of Atoms * @return an Atom representing the Centroid of the set of atoms * @throws StructureException * */ public static final Atom[] centerAtoms(Atom[] atomSet) throws StructureException { Atom centroid = getCentroid(atomSet); return centerAtoms(atomSet, centroid); } /** Center the atoms at the Centroid, if the centroid is already know. * @param atomSet a set of Atoms * @return an Atom representing the Centroid of the set of atoms * @throws StructureException * */ public static final Atom[] centerAtoms(Atom[] atomSet, Atom centroid) throws StructureException { Atom shiftVector = getCenterVector(atomSet, centroid); Atom[] newAtoms = new AtomImpl[atomSet.length]; for (int i =0 ; i < atomSet.length; i++){ Atom a = atomSet[i]; Atom n = add(a,shiftVector); newAtoms[i] = n ; } return newAtoms; } /** creates a virtual C-beta atom. this might be needed when working with GLY * * thanks to Peter Lackner for a python template of this method. * @param amino the amino acid for which a "virtual" CB atom should be calculated * @return a "virtual" CB atom * @throws StructureException */ public static final Atom createVirtualCBAtom(AminoAcid amino) throws StructureException{ AminoAcid ala = StandardAminoAcid.getAminoAcid("ALA"); Atom aN = ala.getN(); Atom aCA = ala.getCA(); Atom aC = ala.getC(); Atom aCB = ala.getCB(); Atom[] arr1 = new Atom[3]; arr1[0] = aN; arr1[1] = aCA; arr1[2] = aC; Atom[] arr2 = new Atom[3]; arr2[0] = amino.getN(); arr2[1] = amino.getCA(); arr2[2] = amino.getC(); // ok now we got the two arrays, do a SVD: SVDSuperimposer svd = new SVDSuperimposer(arr2,arr1); Matrix rotMatrix = svd.getRotation(); Atom tranMatrix = svd.getTranslation(); Calc.rotate(aCB,rotMatrix); Atom virtualCB = Calc.add(aCB,tranMatrix); virtualCB.setName("CB"); return virtualCB; } /** * Gets euler angles for a matrix given in ZYZ convention. * (as e.g. used by Jmol) * * @param m the rotation matrix * @return the euler values for a rotation around Z, Y, Z in degrees... */ public static final double[] getZYZEuler(Matrix m) { double m22 = m.get(2,2); double rY = Math.toDegrees(Math.acos(m22)); double rZ1, rZ2; if (m22 > .999d || m22 < -.999d) { rZ1 = Math.toDegrees(Math.atan2(m.get(1,0), m.get(1,1))); rZ2 = 0; } else { rZ1 = Math.toDegrees(Math.atan2(m.get(2,1), -m.get(2,0))); rZ2 = Math.toDegrees(Math.atan2(m.get(1,2), m.get(0,2))); } return new double[] {rZ1,rY,rZ2}; } /** Convert a rotation Matrix to Euler angles. * This conversion uses conventions as described on page: * http://www.euclideanspace.com/maths/geometry/rotations/euler/index.htm * Coordinate System: right hand * Positive angle: right hand * Order of euler angles: heading first, then attitude, then bank * * @param m the rotation matrix * @return a array of three doubles containing the three euler angles in radians */ public static final double[] getXYZEuler(Matrix m){ double heading, attitude, bank; // Assuming the angles are in radians. if (m.get(1,0) > 0.998) { // singularity at north pole heading = Math.atan2(m.get(0,2),m.get(2,2)); attitude = Math.PI/2; bank = 0; } else if (m.get(1,0) < -0.998) { // singularity at south pole heading = Math.atan2(m.get(0,2),m.get(2,2)); attitude = -Math.PI/2; bank = 0; } else { heading = Math.atan2(-m.get(2,0),m.get(0,0)); bank = Math.atan2(-m.get(1,2),m.get(1,1)); attitude = Math.asin(m.get(1,0)); } return new double[] { heading, attitude, bank }; } /** This conversion uses NASA standard aeroplane conventions as described on page: * http://www.euclideanspace.com/maths/geometry/rotations/euler/index.htm * Coordinate System: right hand * Positive angle: right hand * Order of euler angles: heading first, then attitude, then bank. * matrix row column ordering: * [m00 m01 m02] * [m10 m11 m12] * [m20 m21 m22] * @param heading in radians * @param attitude in radians * @param bank in radians * @return the rotation matrix */ public static final Matrix matrixFromEuler(double heading, double attitude, double bank) { // Assuming the angles are in radians. double ch = Math.cos(heading); double sh = Math.sin(heading); double ca = Math.cos(attitude); double sa = Math.sin(attitude); double cb = Math.cos(bank); double sb = Math.sin(bank); Matrix m = new Matrix(3,3); m.set(0,0, ch * ca); m.set(0,1, sh*sb - ch*sa*cb); m.set(0,2, ch*sa*sb + sh*cb); m.set(1,0, sa); m.set(1,1, ca*cb); m.set(1,2, -ca*sb); m.set(2,0, -sh*ca); m.set(2,1, sh*sa*cb + ch*sb); m.set(2,2, -sh*sa*sb + ch*cb); return m; } /** * Calculates the angle from centerPt to targetPt in degrees. * The return should range from [0,360), rotating CLOCKWISE, * 0 and 360 degrees represents NORTH, * 90 degrees represents EAST, etc... * * Assumes all points are in the same coordinate space. If they are not, * you will need to call SwingUtilities.convertPointToScreen or equivalent * on all arguments before passing them to this function. * * @param centerPt Point we are rotating around. * @param targetPt Point we want to calculate the angle to. * @return angle in degrees. This is the angle from centerPt to targetPt. */ public static double calcRotationAngleInDegrees(Atom centerPt, Atom targetPt) { // calculate the angle theta from the deltaY and deltaX values // (atan2 returns radians values from [-PI,PI]) // 0 currently points EAST. // NOTE: By preserving Y and X param order to atan2, we are expecting // a CLOCKWISE angle direction. double theta = Math.atan2(targetPt.getY() - centerPt.getY(), targetPt.getX() - centerPt.getX()); // rotate the theta angle clockwise by 90 degrees // (this makes 0 point NORTH) // NOTE: adding to an angle rotates it clockwise. // subtracting would rotate it counter-clockwise theta += Math.PI/2.0; // convert from radians to degrees // this will give you an angle from [0->270],[-180,0] double angle = Math.toDegrees(theta); // convert to positive range [0-360) // since we want to prevent negative angles, adjust them now. // we can assume that atan2 will not return a negative value // greater than one partial rotation if (angle < 0) { angle += 360; } return angle; } public static void main(String[] args){ Atom a =new AtomImpl(); a.setX(0); a.setY(0); a.setZ(0); Atom b = new AtomImpl(); b.setX(1); b.setY(1); b.setZ(0); logger.info("Angle between atoms: ", calcRotationAngleInDegrees(a, b)); } public static void rotate(Atom[] ca, Matrix matrix) { for (Atom atom : ca) Calc.rotate(atom, matrix); } /** * Shift an array of atoms at once. * @param ca array of Atoms to shift * @param b reference Atom vector */ public static void shift(Atom[] ca, Atom b) { for (Atom atom : ca) Calc.shift(atom, b); } /** * Convert JAMA rotation and translation to a Vecmath transformation matrix. * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath * matrix is a post-multiplication one, the rotation matrix is transposed to * ensure that the transformation they produce is the same. * * @param rot 3x3 Rotation matrix * @param trans 3x1 Translation matrix * @return 4x4 transformation matrix */ public static Matrix4d getTransformation(Matrix rot, Matrix trans) { return new Matrix4d( new Matrix3d(rot.getColumnPackedCopy()), new Vector3d(trans.getColumnPackedCopy()), 1.0); } /** * Convert JAMA rotation and translation to a Vecmath transformation matrix. * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath * matrix is a post-multiplication one, the rotation matrix is transposed to * ensure that the transformation they produce is the same. * * @param rot 3x3 Rotation matrix * @param trans 3x1 translation vector in Atom coordinates * @return 4x4 transformation matrix */ public static Matrix4d getTransformation(Matrix rot, Atom trans) { return new Matrix4d( new Matrix3d(rot.getColumnPackedCopy()), new Vector3d(trans.getCoords()), 1.0); } /** * Convert Vecmath transformation into a JAMA rotation matrix. * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath * matrix is a post-multiplication one, the rotation matrix is transposed to * ensure that the transformation they produce is the same. * * @param transform Matrix4d with transposed rotation matrix * @return */ public static Matrix getRotationMatrix(Matrix4d transform){ Matrix rot = new Matrix(3,3); for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { rot.set(j, i, transform.getElement(i, j)); //transposed } } return rot; } /** * Extract the translational vector of a Vecmath transformation. * * @param transform Matrix4d * @return Atom shift vector */ public static Atom getTranslationVector(Matrix4d transform){ Atom transl = new AtomImpl(); double[] coords = {transform.m03, transform.m13, transform.m23}; transl.setCoords(coords); return transl; } /** * Convert an array of atoms into an array of vecmath points * @param atoms list of atoms * @return list of Point3ds storing the x,y,z coordinates of each atom */ public static Point3d[] atomsToPoints(Atom[] atoms) { Point3d[] points = new Point3d[atoms.length]; for(int i = 0; i< atoms.length;i++) { points[i] = new Point3d(atoms[i].getCoords()); } return points; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy