/* * This file is part of MoleculeViewer. * * MoleculeViewer 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 3 of the License, or * (at your option) any later version. * * MoleculeViewer 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 MoleculeViewer. If not, see <http://www.gnu.org/licenses/>. */ package astex; import javax.vecmath.Vector3d; /* Copyright Astex Technology Ltd. 1999 */ /* Copyright David Hall, Boston University, 2011 */ /* * 01-11-99 mjh * created */ /** * A class for manipulating 3d points and vectors. */ public class Point3d extends Vector3d implements Cloneable { /** * Default constructor. * * The x, y and z coordinates are set to 0.0 */ public Point3d(){ super(); } /** * Constructor which allows the x, y, and z coordinates to be specified. */ public Point3d(double xx, double yy, double zz){ super(xx,yy,zz); } /** * Construct a 2D point with specified x and y coordinates. * * The z coordinates is set to 0.0 */ public Point3d(double xx, double yy){ this(xx, yy, 0.0); } /** * Clone method */ @Override public Point3d clone() { return (Point3d) super.clone(); } /** Set the specified component. */ public double get(int i){ switch(i){ case 0: return x; case 1: return y; case 2: return z; default: System.out.println("Point3d.get: can't get component "+ i); } return Double.MAX_VALUE; } /** Set the specified component. */ public void set(int i, double v){ switch(i){ case 0: x = v; return; case 1: y = v; return; case 2: z = v; return; default: System.out.println("Point3d.set: can't set component " + i); } } /** * Set the x, y and z coordinates to 0.0 * * Transformed and screen space coordinates are not affected. */ public void zero(){ set(0.0, 0.0, 0.0); } /** * Construct a point with the x, y and z coordinates equal to the * midpoint of two other Point3ds. */ public static Point3d mid(Point3d pmin, Point3d pmax){ Point3d middle = new Point3d(); middle.x = 0.5 * (pmin.x + pmax.x); middle.y = 0.5 * (pmin.y + pmax.y); middle.z = 0.5 * (pmin.z + pmax.z); return middle; } /** * Construct a point with the x, y and z coordinates equal to the * midpoint of two other Point3ds. */ public static void mid(Point3d pmid, Point3d pmin, Point3d pmax){ pmid.x = 0.5 * (pmin.x + pmax.x); pmid.y = 0.5 * (pmin.y + pmax.y); pmid.z = 0.5 * (pmin.z + pmax.z); } /** * Return another point, which is at the mid point of two points. */ public static Point3d unitVector(Point3d p1, Point3d p2){ /* Make a unit vector from p1 to p2. */ Point3d unit = new Point3d(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z); unit.normalize(); return unit; } /** Set first point to be unitVector from p1 to p2. */ public static void unitVector(Point3d up12, Point3d p1, Point3d p2){ /* Make a unit vector from p1 to p2. */ up12.set(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z); up12.normalize(); } /** * Generate a vector from the first point to the second. * * The vector does not have a length of 1. */ public static Point3d vector(Point3d p1, Point3d p2){ /* Make a vector from p1 to p2. */ Point3d unit = new Point3d(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z); return unit; } /** * Construct a unit vector that is perpendicular to the vector. * * If p is the null vector then (1.,1.,.1) is returned. */ public static Point3d normalToLine(Point3d p){ /* * Construct a unit vector that is perpendicular to * the vector described by p. If p is the null * vector then (1.,1.,.1) is returned. */ Point3d normal = new Point3d(1., 1., 1.); if(p.x != 0.) normal.x = (p.z + p.y) / -p.x; else if(p.y != 0.) normal.y = (p.x + p.z) / -p.y; else if(p.z != 0.) normal.z = (p.x + p.y) / -p.z; normal.normalize(); return normal; } /** * Construct a unit vector that is perpendicular to the vector. */ public static void normalToLine(Point3d p, Point3d n){ /* * Construct a unit vector that is perpendicular to * the vector described by p. If p is the null * vector then (1.,1.,.1) is returned. */ n.set(1., 1., 1.); if(p.x != 0.) n.x = (p.z + p.y) / -p.x; else if(p.y != 0.) n.y = (p.x + p.z) / -p.y; else if(p.z != 0.) n.z = (p.x + p.y) / -p.z; n.normalize(); } /** Return cross product with c. */ public Point3d cross(Point3d c){ Point3d a = new Point3d(); a.cross(this, c); a.normalize(); return a; } /** Set a to cross product of b and c. */ public static void cross(Point3d a, Point3d b, Point3d c){ a.cross(b,c); a.normalize(); } /** Set a to cross product of b and c. */ public static void crossNoNormalise(Point3d a, Point3d b, Point3d c){ a.cross(b,c); } /** Generate cross product for double[] vectors. */ public static void cross(double a[], double b[], double c[]){ a[0] = (b[1] * c[2]) - (b[2] * c[1]); a[1] = (b[2] * c[0]) - (b[0] * c[2]); a[2] = (b[0] * c[1]) - (b[1] * c[0]); } /** * Return the distance to the specified point. */ public double distance(Point3d p){ double dx = p.x - x; double dy = p.y - y; double dz = p.z - z; return(Math.sqrt(dx*dx + dy*dy + dz*dz)); } /** Return the square of the distance to the specified point. */ public double distanceSquared(Point3d p){ double dx = p.x - x; double dy = p.y - y; double dz = p.z - z; return(dx*dx + dy*dy + dz*dz); } /** Scale a vector by the amount specified for each coordinate. */ public void divide(double s){ scale(1/s); } /** Calculate the angle between the 3 points. */ public static double angle(Point3d a, Point3d b, Point3d c){ double xba = a.x - b.x, yba = a.y - b.y, zba = a.z - b.z; double xbc = c.x - b.x, ybc = c.y - b.y, zbc = c.z - b.z; double ba = Math.sqrt(xba*xba + yba*yba + zba*zba); double bc = Math.sqrt(xbc*xbc + ybc*ybc + zbc*zbc); double dot = xba*xbc + yba*ybc + zba*zbc; dot /= (ba * bc); return Math.acos(dot); } /** Calculate the angle in degrees. */ public static double angleDegrees(Point3d a, Point3d b, Point3d c){ return 180.0 * angle(a, b, c) / Math.PI; } /** Calculate the torsion angle between the 4 points. */ public static double torsion(Point3d p1, Point3d p2, Point3d p3, Point3d p4){ Point3d v1, v2, v3; Point3d n1, n2; double angle; /* generate vectors between points (and normalise) */ v1 = unitVector(p1, p2); v2 = unitVector(p2, p3); v3 = unitVector(p3, p4); /* form xprods and normalise */ n1 = v1.cross(v2); n1.normalize(); n2 = v2.cross(v3); n2.normalize(); /* * get the angle between xprods and figure out whether to negate it * * if n1 points in the opposite direction to v3 the angle should be * negated */ double dot = n1.dot(n2); // ensure that the dot product lies // within -1.0/+1.0 if(dot > 1.0) dot = 1.0; else if(dot < -1.0) dot = -1.0; angle = Math.acos(dot); if(n1.dot(v3) < 0.0) angle = -angle; return angle; } /** Calculate torsion in degrees. */ public static double torsionDegrees(Point3d p1, Point3d p2, Point3d p3, Point3d p4){ return 180.0 * torsion(p1, p2, p3, p4) / Math.PI; } /** Transform this atom to screen coordinates. */ public void transform(Matrix m){ double xx = x*m.m00 + y*m.m10 + z*m.m20 + m.m30; double yy = x*m.m01 + y*m.m11 + z*m.m21 + m.m31; double zz = x*m.m02 + y*m.m12 + z*m.m22 + m.m32; x = xx; y = yy; z = zz; } /** Return a string representation of this point. */ @Override public String toString(){ return String.format("%8.3f", x) + String.format("%8.3f", y) + String.format("%8.3f", z); } }