/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
* Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
* This source code is released under a BSD License, which allows redistribution
* in source and binary form, with or without modification, provided copyright
* and license information are included, and with no warranty or guarantee of
* any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
*/
package vmm.core3D;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import vmm.core.Util;
/**
* A 3D vector with components of type double named x, y, and z.
*/
public class Vector3D {
/**
* The first component of the vector.
*/
public double x;
/**
* The second component of the vector.
*/
public double y;
/**
* The third component of the vector.
*/
public double z;
/**
* The origin, (0,0,0).
*/
public static final Vector3D ORIGIN = new Vector3D(0,0,0);
/**
* The unit vector in the x direction, (1,0,0).
*/
public static final Vector3D UNIT_X = new Vector3D(1,0,0);
/**
* The unit vector in the y direction, (0,1,0).
*/
public static final Vector3D UNIT_Y = new Vector3D(0,1,0);
/**
* The uint vector in the z direction, (0,0,1).
*/
public static final Vector3D UNIT_Z = new Vector3D(0,0,1);
/**
* Construct a vector with all three components initially equal to zero.
*/
public Vector3D() {
}
/**
* Construct a vector that initially has coordinates (x,y,z).
*/
public Vector3D(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Construct a vector that is initially a copy of a specified vector.
* @param v the constructed vector is (v.x, v.y, v.z), or is (0,0,0) if v is null.
*/
public Vector3D(Vector3D v) {
if (v == null)
x = y = z = 0;
else {
x = v.x;
y = v.y;
z = v.z;
}
}
/**
* Returns true obj is a non-null object whose class in Vector3D and such that
* the three corrdinates of the vector obj are the same as the coordinates of this
* vector.
*/
public boolean equals(Object obj) {
if (obj == null || ! (obj.getClass().equals(Vector3D.class)))
return false;
Vector3D v = (Vector3D)obj;
return v.x == x && v.y == y && v.z == z;
}
/**
* Returns the length of this vector, computed as Math.sqrt(x*x+y*y+z*z)
*/
public double norm() {
return Math.sqrt(x*x + y*y + z*z);
}
/**
* Returns the length^2 of this vector, computed as (x*x+y*y+z*z)
*/
public double norm2() {
return (x*x + y*y + z*z);
}
/**
* Divides each component of the vector by the norm of the vector, giving a vector that has length 1.
* However, if the vector is zero, or if any of its components are infinite or undefined, then the
* result of calling this method is to set all the components of the vector to Double.NaN.
* This method modifies the vector.
* @see #normalized()
*/
public void normalize() {
double lengthRecip = 1.0 / Math.sqrt(x*x + y*y + z*z);
if ( Double.isNaN(lengthRecip) || Double.isInfinite(lengthRecip) )
x = y = z = Double.NaN;
else {
this.x *= lengthRecip;
this.y *= lengthRecip;
this.z *= lengthRecip;
}
}
/**
* Multiplies each component of this vector by -1. This method modifies the vector.
* @see #negated()
*/
public void negate() {
x = -x;
y = -y;
z = -z;
}
/**
* Returns a new vector that is equal to this vector normalized. This vector is not modified.
* @see #normalize()
*/
public Vector3D normalized() {
Vector3D v = new Vector3D(x,y,z);
v.normalize();
return v;
}
/**
* Returns a new vector that is equal to -1 times this vector. This vector is not modified.
* @see #negate()
*/
public Vector3D negated() {
return new Vector3D(-x,-y,-z);
}
/**
* Returns the vector sum of this vector and v. A new vector object is constructed to contain
* the result; neither input vector is modified.
* @param v a non-null vector
*/
public Vector3D plus(Vector3D v) {
return new Vector3D(x + v.x, y + v.y, z + v.z);
}
/**
* Returns the linear combination c*this + d*v. A new vector object contains the result.
*/
public Vector3D linComb(double c, double d,Vector3D v) {
return new Vector3D(c*x + d*v.x, c*y + d*v.y, c*z + d*v.z);
}
/**
* this.assign(v) assigns to this the value v.
*/
public void assign(Vector3D v) {
x = v.x; y = v.y; z = v.z;
}
/**
* this.assignPlus(v) assigns to this the value this + v.
*/
public void assignPlus(Vector3D v) {
x += v.x; y += v.y; z += v.z;
}
/**
* this.assignSum(v,w) assigns to this the value v + w.
*/
public void assignSum(Vector3D v, Vector3D w) {
x = v.x + w.x; y = v.y + w.y; z = v.z + w.z;
}
/**
* this.assignLinComb(c,d,v) assigns to this the value c*this + d*v.
*/
public void assignLinComb(double c, double d, Vector3D v) {
x = c*x + d*v.x; y = c*y + d*v.y; z = c*z + d*v.z;
}
/**
* this.assignLinComb(c,v,d,w) assigns to this the value c*v + d*w.
*/
public void assignLinComb(double c, Vector3D v, double d, Vector3D w) {
x = c*v.x + d*w.x; y = c*v.y + d*w.y; z = c*v.z + d*w.z;
}
/**
* this.assignPlus_SumTimes(u, v, w, ww, d) assigns to this the value: this + (u + v + w + ww)*d.
*/
public void assignPlus_SumTimes(Vector3D u, Vector3D v, Vector3D w, Vector3D ww, double d) {
x += d*(u.x + v.x + w.x + ww.x); y += d*(u.y + v.y + w.y + ww.y);
z += d*(u.z + v.z + w.z + ww.z);
}
/**
* Returns the vector difference of this vector and v. A new vector object is constructed to contain
* the result; neither input vector is modified.
* @param v a non-null vector
*/
public Vector3D minus(Vector3D v) {
return new Vector3D(x - v.x, y - v.y, z - v.z);
}
/**
* this.assignMinus(v) assigns to this the value this (- v).
*/
public void assignMinus(Vector3D v) {
x -= v.x; y -= v.y; z -= v.z;
}
/**
* this.assignMinus(v, w) assigns to this the value this (v - w).
*/
public void assignMinus(Vector3D v, Vector3D w) {
x = v.x - w.x; y = v.y - w.y; z = v.z - w.z;
}
/**
* Returns the scalar product of this vector times d. A new vector object is constructed to contain
* the result; the vector is not modified.
* @param d the scalar that is to be multiplied times this vector
*/
public Vector3D times(double d) {
return new Vector3D(d*x, d*y, d*z);
}
/**
* this.assignTimes(d) assigns to this the value d*this.
*/
public void assignTimes(double d) {
x *= d; y *= d; z *= d;
}
/**
* this.assignTimes(d, v) assigns to this the value d*v.
*/
public void assignTimes(double d, Vector3D v) {
x = d*v.x; y = d*v.y; z = d*v.z;
}
/**
* this.assignSumTimes(v, w, d) assigns to this the value (v + w)*d.
*/
public void assignSumTimes(Vector3D v, Vector3D w, double d) {
x = d*(v.x + w.x); y = d*(v.y + w.y); z = d*(v.z + w.z);
}
/**
* this.assignSumTimes(v, w, vv, ww, d) assigns to this the value (v + w + vv + ww)*d.
*/
public void assignSumTimes(Vector3D v, Vector3D w, Vector3D vv, Vector3D ww, double d) {
x = d*(v.x + w.x + vv.x + ww.x); y = d*(v.y + w.y + vv.y + ww.y); z = d*(v.z + w.z + vv.z + ww.z);
}
/**
* Returns the dot product of this vector and v. A new vector object is constructed to contain
* the result; neither input vector is modified.
* @param v a non-null vector
*/
public double dot(Vector3D v) {
return x*v.x + y*v.y + z*v.z;
}
/**
* Returns the cross product of this vector and v. A new vector object is constructed to contain
* the result; neither input vector is modified.
* @param v a non-null vector
*/
public Vector3D cross(Vector3D v) {
double x1 = (y * v.z) - (v.y * z);
double y1 = -(x * v.z) + (v.x * z);
double z1 = (x * v.y) - (v.x * y);
return new Vector3D(x1,y1,z1);
}
/**
* Rotates this around the unit vector axis by 180 degrees: this to -this + 2*axis.
* Call as this.reflectInAxis(axis).
*/
public Vector3D reflectInAxis(Vector3D axis) {
double s = 2 * (axis.x * x + axis.y * y + axis.z * z);
Vector3D destination = new Vector3D(s*axis.x - x,s*axis.y - y,s*axis.z - z);
return destination;
}
/**
* Why can't the following version not be called by SphericalCycloid?
public static Vector3D reflectInAxis(Vector3D axis, Vector3D source) {
double s = 2 * (axis.x * source.x + axis.y * source.y + axis.z * source.z);
Vector3D destination = new Vector3D(s*axis.x - source.x,s*axis.y - source.y,s*axis.z - source.z);
return destination;
}
*/
/**
* Returns a string representation of this vector of the form "(x,y,z)" where x, y, and z are
* the numerical components of the vector. The special strings NaN, INF and -INF are used to
* represent the values Double.NaN, Double.POSITIVE_INFINITY, and Double.NEGATIVE_INFINITY.
*/
public String toString() {
String xStr = Util.toExternalString(x);
String yStr = Util.toExternalString(y);
String zStr = Util.toExternalString(z);
return "(" + xStr + "," + yStr + "," + zStr + ")";
}
/**
* Attempts to convert a string into a value of type Vector3D. The string should be
* in the format produced by {@link #toString()}, of the form "(x,y,z)". Will also accept strings
* that use a space as a separator and are not enclosed in parentheses, of the form "x y z".
* @param str the non-null string that is to be converted
* @throws NumberFormatException if the string is not of the correct format (or is null)
*/
public static Vector3D fromString(String str) throws NumberFormatException {
try {
Matcher matcher = Pattern.compile("\\((.*),(.*),(.*)\\)").matcher(str);
if (! matcher.matches() ) {
matcher = Pattern.compile("(.*) (.*) (.*)").matcher(str.trim());
if (! matcher.matches())
throw new Exception();
}
String xStr = matcher.group(1);
String yStr = matcher.group(2);
String zStr = matcher.group(3);
double x = (Double)Util.externalStringToValue(xStr, Double.TYPE);
double y = (Double)Util.externalStringToValue(yStr, Double.TYPE);
double z = (Double)Util.externalStringToValue(zStr, Double.TYPE);
return new Vector3D(x,y,z);
}
catch (Exception e) {
throw new NumberFormatException("Can't convert string to Vector3D");
}
}
}