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

org.xmlcml.euclid.Vector3 Maven / Gradle / Ivy

/**
 *    Copyright 2011 Peter Murray-Rust
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.xmlcml.euclid;

import org.xmlcml.euclid.Axis.Axis3;

/**
 * 3-dimensional vector
 *
 * A vector has thre components giving it a length and a direction (whose sign
 * is important),but no position. Vectors are often normalised to unit length.
 * 

* Vectors and points are very closely related and some people use them * interchangeably. A Point3 has a position and cannot be normalised. In * very many routines, however, Vectors and Points can either be used * interchangeably, or there are equivalent routines or they can be converted * using cross-constructors. (They cannot be interconverted through casts). *

* The default vector is 0.0, 0.0, 0.0. Some operations on this will result in * ZerolengthVector Exceptions. * * @author (C) P. Murray-Rust, 1996 */ public class Vector3 implements EuclidConstants { /** * length of vector is zero */ final static int ZERO_VECT = 0; /** * length of vector is unknown */ final static int UNK_VECT = 1; /** * length is unit vector */ final static int UNIT_VECT = 2; /** * length of vector not zero or unity */ final static int OK_VECT = 3; /** * zero-length vector */ public final static Vector3 ZEROV = new Vector3(0.0, 0.0, 0.0); /** * X axis */ public final static Vector3 XV = new Vector3(1.0, 0.0, 0.0); /** * Y axis */ public final static Vector3 YV = new Vector3(0.0, 1.0, 0.0); /** * Z axis */ public final static Vector3 ZV = new Vector3(0.0, 0.0, 1.0); /** * Vector3 includes protected members which keep track of the sort of vector * At present these can be: null vector, unit vector and unknown. These * serve to reduce repetition in normalising already normalised vectors */ /** * vector status */ // int vecstatus = UNK_VECT; /** * vector length IF status not UNK_VECT, else -1 */ // double veclength; /** * vector components */ double[] flarray = new double[3]; /** * null constructor */ public Vector3() { } /** * construct from vector components. * * @param x * component * @param y * component * @param z * component */ public Vector3(double x, double y, double z) { this(); flarray[0] = x; flarray[1] = y; flarray[2] = z; } /** * construct from vector components. * * @param array * components * @throws EuclidRuntimeException */ public Vector3(double[] array) throws EuclidRuntimeException { this(); Util.check(array, 3); System.arraycopy(array, 0, flarray, 0, 3); } /** * axial unit vector constructor. unit vectors along X, Y, Z axes * * @param axis * to use */ public Vector3(Axis3 axis) { this(); Real.zeroArray(3, flarray); flarray[axis.value] = 1.0; } /** * copy constructor: * * @param v * vector to copy */ public Vector3(Vector3 v) { this(); System.arraycopy(v.flarray, 0, flarray, 0, 3); } /** * copy constructor from RealArray. * * @param f the array (of length 3) * @throws EuclidRuntimeException */ public Vector3(RealArray f) throws EuclidRuntimeException { this(); RealArray.check(f, 3); System.arraycopy(f.getArray(), 0, flarray, 0, 3); } /** * make a vector from a point vector is from origin to point * * @param p * the point */ public Vector3(Point3 p) { this(); System.arraycopy(p.flarray, 0, flarray, 0, 3); } /** * copy constructor: synonym for copy constructor * * @param v * vector to copy * @return vector */ public Vector3 clone(Vector3 v) { System.arraycopy(v.flarray, 0, flarray, 0, 3); return this; } /** * from Point3 vector is from origin to point * * @param p * the point * @return vector */ public Vector3 clone(Point3 p) { System.arraycopy(p.flarray, 0, flarray, 0, 3); return this; } /** * get the vector components * * @return vector of length 3 */ public double[] getArray() { return flarray; } /** * are two vectors equal lengths. uses Real.isEqual * * @param v * @return equal if length difference is within tolerance */ public boolean isEqualTo(Vector3 v) { return Real.isEqual(getLength(), v.getLength()); } /** * vector length {@literal >} vector length * * @param v * vector to compare * @return true if this {@literal >} vector */ public boolean longerThan(Vector3 v) { return (getLength() > v.getLength()); } /** * scalar multiplication. create new vector vector = this*f does not alter this * * @param f * multiplier for all components * @return scaled vector */ public Vector3 multiplyBy(double f) { Vector3 v1 = new Vector3(this); for (int i = 0; i < 3; i++) { v1.flarray[i] *= f; } return v1; } /** * scalar multiplication. sets equal to this*f alters this * * @param f * multiplier for all components */ public void multiplyEquals(double f) { for (int i = 2; i >= 0; --i) { flarray[i] *= f; } } /** * vector addition. create new vector result = this + v3 does not alter this * * @param v3 * vector to add * @return resultant vector */ public Vector3 plus(Vector3 v3) { Vector3 v1 = new Vector3(); v1 = this; for (int i = 0; i < 3; i++) { v1.flarray[i] += v3.flarray[i]; } return v1; } /** * vector addition. sets equal to this + v3 alters this * * @param v3 vector to subtract */ public void plusEquals(Vector3 v3) { for (int i = 2; i >= 0; --i) { flarray[i] += v3.flarray[i]; } } /** * vector subtraction. create new vector result = this - v3 does not alter * this * * @param v3 * vector to subtract * @return resultant vector */ public Vector3 subtract(Vector3 v3) { Vector3 v1 = new Vector3(); v1 = this; for (int i = 0; i < 3; i++) { v1.flarray[i] -= v3.flarray[i]; } return v1; } /** * vector subtraction. sets equal to this - v3 alters this * * @param v3 vector to subtract */ public void subtractEquals(Vector3 v3) { for (int i = 2; i >= 0; --i) { flarray[i] -= v3.flarray[i]; } } /** * negative of vector. result = -this does not alter this * * @return resultant vector */ public Vector3 negative() { Vector3 v1 = new Vector3(this); for (int i = 0; i < 3; i++) { v1.flarray[i] = -flarray[i]; } return v1; } /** * negative of vector. result = - DOES alter this * * @return resultant vector */ public Vector3 negativeEquals() { for (int i = 0; i < 3; i++) { flarray[i] = -flarray[i]; } return this; } /** * get component. use raw array if you are sure checking is not required * * @param n * the zero-based index * @return the n'th component * @throws EuclidRuntimeException */ public double elementAt(int n) throws EuclidRuntimeException { Util.check(n, 0, 2); return flarray[n]; } /** * set component. * * @param n * the zero-based index * @param f * component value * @throws EuclidRuntimeException */ public void setElementAt(int n, double f) throws EuclidRuntimeException { Util.check(n, 0, 2); flarray[n] = f; } /** * are two vectors equal in all components. uses Real.isEqual * * @param v * @return equal if components equal within tolerance */ public boolean isIdenticalTo(Vector3 v) { return Real.isEqual(flarray, v.flarray, Real.getEpsilon()); } /** * is vector of zero length. uses Real.isEqual * * @return if zero within tolerance */ public boolean isZero() { boolean b = Real.isZero(getLength(), Real.getEpsilon()); return b; } /** * create transformed vector. does not alter this. * * @param t * transform * @return tranformed vector */ public Vector3 transform(Transform3 t) { Transform3.checkNotNull(t); Vector3 vout = new Vector3(); double[] pv = vout.flarray; double[][] pt = t.getMatrix(); // just use the 3x3 submatrix and ignore translation for (int i = 0; i < 3; i++) { double[] p = this.flarray; for (int j = 0; j < 3; j++) { pv[i] += pt[i][j] * p[j]; } } return vout; } /** * create cross product. result = this x v3 does not alter this. * * @param v3 * vector to multiply * @return cross product */ public Vector3 cross(Vector3 v3) { Vector3 v1 = new Vector3(); int i, j, k; for (i = 0, j = 1, k = 2; i < 3; i++) { v1.flarray[i] = flarray[j] * v3.flarray[k] - flarray[k] * v3.flarray[j]; j = (j + 1) % 3; k = (k + 1) % 3; } return v1; } /** sets vector components to nearest integer value. * useful for crystallography and other grids * uses Math.round(); * ALTERS THIS * @return vector with integer components */ public Vector3 round() { for (int i = 0; i < 3; i++) { flarray[i] = Math.round(flarray[i]); } return this; } /** normalize vector. * alters this * this = this.normalize() * if zero vector takes no action (maybe this is bad...) * * @return vector of unit length */ public Vector3 normalize() { double veclength = this.getLength(); if (veclength < EPS) { throw new EuclidRuntimeException("cannot normalize zero-length vector"); } for (int i = 0; i < 3; i++) { flarray[i] /= veclength; } return this; } /** normalize vector. alters this this = this.normalize() if zero vector * takes no action (maybe this is bad...) * @deprecated (use normalize()) * @return vector of unit length */ public Vector3 normalise() { return this.normalize(); } /** * get normalized vector. * does not alter this * result = this.normalize() * if zero vector takes no action (maybe this is bad...) * * @return vector of unit length */ public Vector3 getUnitVector() { Vector3 v = new Vector3(this); v.normalize(); return v; } /** * return vector length. does not alter this result = this.length() * * @return vector length */ public double getLength() { double sum = 0.0; for (int i = 0; i < 3; i++) { sum += flarray[i] * flarray[i]; } return Math.sqrt(sum); } /** * create dot product. result = this . v3 does not alter this. * * @param v3 * vector to multiply * @return dot product */ public double dot(Vector3 v3) { double sum = 0.0; for (int i = 0; i < 3; i++) { sum += this.flarray[i] * v3.flarray[i]; } return sum; } /** * dot product - protected * * @param v3 * @return the dotproduct */ protected double dot(double[] v3) { double sum = 0.0; for (int i = 0; i < 3; i++) { sum += this.flarray[i] * v3[i]; } return sum; } /** * calculate unsigned angle between vectors result = angle between this and * v2 uses acos(this.dot.v2) so angle is unsigned does not alter this. * * @param v2 * vector to multiply * @return angle (null if vectors zero length */ public Angle getAngleMadeWith(Vector3 v2) { Angle a = null; if (!this.isZero() && !v2.isZero()) { Vector3 v1a = getUnitVector(); Vector3 v2a = v2.getUnitVector(); double tmp = v1a.dot(v2a); if (tmp < -1.0) { tmp = -1.0; } else if (tmp > 1.0) { tmp = 1.0; } a = new Angle(Math.acos(tmp)); } return a; } /** * calculate scalar triple product between vectors. result = this.(v2 x v3) * does not alter this. * * @param v2 * vector to multiply * @param v3 * vector to multiply * @return stp */ public double getScalarTripleProduct(Vector3 v2, Vector3 v3) { return this.dot(v2.cross(v3)); } /** * projection of this onto vector. does not alter this. result = vector.norm() * * (this.norm() dot vector.norm()) * * @param v * vector to project onto * @exception EuclidRuntimeException * vector or this is zero length * @return projected vector */ public Vector3 projectOnto(Vector3 v) throws EuclidRuntimeException { if (this.isZero() || v.isZero()) { throw new EuclidRuntimeException("zero length vector"); } Vector3 projection = new Vector3(); Vector3 unit3 = v.getUnitVector(); Vector3 unit2 = getUnitVector(); double dot = unit2.dot(unit3); projection = unit3.multiplyBy(getLength() * dot); return projection; } /** * are two vectors colinear. also returns true if one or more vectors are * zero * * @param v * vector to test with this * @return true if cross product isZero() */ public boolean isColinearVector(Vector3 v) { return this.cross(v).isZero(); } /** * get any vector not colinear with this. returns any axis which is not * colinear with this * * @return either XV or YV (even if this is zero) */ public Vector3 getNonColinearVector() { return isColinearVector(XV) ? YV : XV; } /** * get any vector perpendicular to this. useful for creating cartesian axes * containing this * * @return vector perpendicular to this (zero if this is zero) */ public Vector3 getPerpendicularVector() { return this.isZero() ? ZEROV : this.getNonColinearVector().cross(this); } /** * get string representation. * * @return string representation */ public String toString() { return EuclidConstants.S_LBRAK + flarray[0] + EuclidConstants.S_COMMA + flarray[1] + EuclidConstants.S_COMMA + flarray[2] + EuclidConstants.S_RBRAK; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy