From 1a396193a5c565d5c74692e2acd1622acebf6d61 Mon Sep 17 00:00:00 2001 From: benfry Date: Mon, 29 Sep 2008 17:47:15 +0000 Subject: [PATCH] cleanup and changes to make PVector part of the core --- core/src/processing/core/PVector.java | 416 +++++++++++++++++++------- 1 file changed, 301 insertions(+), 115 deletions(-) diff --git a/core/src/processing/core/PVector.java b/core/src/processing/core/PVector.java index e46635b1f..586e41314 100644 --- a/core/src/processing/core/PVector.java +++ b/core/src/processing/core/PVector.java @@ -3,8 +3,8 @@ /* Part of the Processing project - http://processing.org - Copyright (c) 2004-07 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology + Copyright (c) 200X Dan Shiffman + Copyright (c) 2008 Ben Fry and Casey Reas This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,8 +25,17 @@ package processing.core; /** - * A class to describe a two or three dimensional vector. - *
+ * A class to describe a two or three dimensional vector. When + *

+ * The result of all functions are applied to the vector itself, with the + * exception of cross(), which returns a new PVector (or writes to a specified + * 'target' PVector). That is, add() will add the contents of one vector to + * this one. Using add() with additional parameters allows you to put the + * result into a new PVector. Functions that act on multiple vectors also + * include static versions. Because creating new objects can be computationally + * expensive, most functions include an optional 'target' PVector, so that a + * new PVector object is not created with each operation. + *

* Initially based on the Vector3D class by Dan Shiffman. */ public class PVector { @@ -78,7 +87,7 @@ public class PVector { /** * Set the x coordinate. * - * @param x the x coordinate. + * @param x the x coordinate. */ public void setX(float x) { this.x = x; @@ -87,7 +96,7 @@ public class PVector { /** * Set the y coordinate. * - * @param y the y coordinate. + * @param y the y coordinate. */ public void setY(float y) { this.y = y; @@ -97,7 +106,7 @@ public class PVector { /** * Set the z coordinate. * - * @param z the z coordinate. + * @param z the z coordinate. */ public void setZ(float z) { this.z = z; @@ -105,11 +114,11 @@ public class PVector { /** - * Set x,y, and z coordinates. + * Set x, y, and z coordinates. * - * @param x_ the x coordinate. - * @param y_ the y coordinate. - * @param z_ the z coordinate. + * @param x the x coordinate. + * @param y the y coordinate. + * @param z the z coordinate. */ public void set(float x, float y, float z) { this.x = x; @@ -119,64 +128,167 @@ public class PVector { /** - * Set x,y, and z coordinates from a Vector3D object. - * - * @param v the Vector3D object to be copied + * Set x, y, and z coordinates from a Vector3D object. + * + * @param v the PVector object to be copied */ - public void setXYZ(PVector v) { + public void set(PVector v) { x = v.x; y = v.y; z = v.z; } + + + /** + * Set the x, y (and maybe z) coordinates using a float[] array as the source. + * @param source array to copy from + */ + public void set(float[] source) { + if (source.length >= 2) { + x = source[0]; + y = source[1]; + } + if (source.length >= 3) { + z = source[2]; + } + } + + + /** + * Get a copy of this vector. + * @return + */ + public PVector get() { + return new PVector(x, y, z); + } + /** - * Calculate the magnitude (length) of the vector - * @return the magnitude of the vector + * + * @param target + * @return */ - public float magnitude() { + public float[] get(float[] target) { + if (target == null) { + return new float[] { x, y, z }; + } + if (target.length >= 2) { + target[0] = x; + target[1] = y; + } + if (target.length >= 3) { + target[2] = z; + } + return target; + } + + + /** + * Copy the vector (synonym for get()). + * @return a copy of the vector + */ + public PVector copy() { + return new PVector(x, y, z); + } + + + /** + * Calculate the magnitude (length) of the vector + * @return the magnitude of the vector + */ + public float mag() { return (float) Math.sqrt(x*x + y*y + z*z); } - /** - * Copy the vector - * @return a copy of the vector - */ - public PVector copy() { - return new PVector(x,y,z); - } - - /** - * Copy the vector - * @param v the vector to be copied - * @return a copy of the vector - */ - public static PVector copy(PVector v) { - return new PVector(v.x, v.y,v.z); - } /** * Add a vector to this vector - * @param v the vector to be added - */ + * @param v the vector to be added + */ public void add(PVector v) { x += v.x; y += v.y; z += v.z; } + + + public void add(float x, float y, float z) { + this.x += x; + this.y += y; + this.z += z; + } + + + /** + * Add two vectors + * @param v1 a vector + * @param v2 another vector + * @return a new vector that is the sum of v1 and v2 + */ + static public PVector add(PVector v1, PVector v2) { + return add(v1, v2, null); + } + + /** + * Add two vectors into a target vector + * @param v1 a vector + * @param v2 another vector + * @param target the target vector (if null, a new vector will be created) + * @return a new vector that is the sum of v1 and v2 + */ + static public PVector add(PVector v1, PVector v2, PVector target) { + if (target == null) { + target = new PVector(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z); + } else { + target.set(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); + } + return target; + } + + /** * Subtract a vector from this vector - * @param v the vector to be subtracted + * @param v the vector to be subtracted */ public void sub(PVector v) { x -= v.x; y -= v.y; z -= v.z; } + + + public void sub(float x, float y, float z) { + this.x -= x; + this.y -= y; + this.z -= z; + } + + + /** + * Subtract one vector from another + * @param v1 a vector + * @param v2 another vector + * @return a new vector that is v1 - v2 + */ + static public PVector sub(PVector v1, PVector v2) { + return sub(v1, v2, null); + } + + + static public PVector sub(PVector v1, PVector v2, PVector target) { + if (target == null) { + target = new PVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } else { + target.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + return target; + } + /** * Multiply this vector by a scalar - * @param n the value to multiply by + * @param n the value to multiply by */ public void mult(float n) { x *= n; @@ -184,9 +296,38 @@ public class PVector { z *= n; } + + /** + * Multiply a vector by a scalar + * @param v a vector + * @param n scalar + * @return a new vector that is v1 * n + */ + static public PVector mult(PVector v, float n) { + return mult(v, n, null); + } + + + /** + * Multiply a vector by a scalar, and write the result into a target PVector. + * @param v a vector + * @param n scalar + * @param target PVector to store the result + * @return the target vector, now set to v1 * n + */ + static public PVector mult(PVector v, float n, PVector target) { + if (target == null) { + target = new PVector(v.x*n, v.y*n, v.z*n); + } else { + target.set(v.x*n, v.y*n, v.z*n); + } + return target; + } + + /** * Divide this vector by a scalar - * @param n the value to divide by + * @param n the value to divide by */ public void div(float n) { x /= n; @@ -194,48 +335,151 @@ public class PVector { z /= n; } - + /** - * Calculate the dot product with another vector - * @return the dot product - */ - public float dot(PVector v) { - float dot = x*v.x + y*v.y; - return dot; + * Divide a vector by a scalar and return the result in a new vector. + * @param v a vector + * @param n scalar + * @return a new vector that is v1 / n + */ + static public PVector div(PVector v, float n) { + return div(v, n, null); + } + + + static public PVector div(PVector v, float n, PVector target) { + if (target == null) { + target = new PVector(v.x/n, v.y/n, v.z/n); + } else { + target.set(v.x/n, v.y/n, v.z/n); + } + return target; } + /** - * Calculate the cross product with another vector - * @return the cross product + * Calculate the Euclidean distance between two points (considering a point as a vector object) + * @param v another vector + * @return the Euclidean distance between + */ + public float dist(PVector v) { + float dx = x - v.x; + float dy = y - v.y; + float dz = z - v.z; + return (float) Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + + /** + * Calculate the Euclidean distance between two points (considering a point as a vector object) + * @param v1 a vector + * @param v2 another vector + * @return the Euclidean distance between v1 and v2 + */ + static public float dist(PVector v1, PVector v2) { + float dx = v1.x - v2.x; + float dy = v1.y - v2.y; + float dz = v1.z - v2.z; + return (float) Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + + /** + * Calculate the dot product with another vector + * @return the dot product */ + public float dot(PVector v) { + return x*v.x + y*v.y + z*v.z; + } + + + public float dot(float x, float y, float z) { + return this.x*x + this.y*y + this.z*z; + } + + + /** + * Return a vector composed of the cross product between this and another. + */ public PVector cross(PVector v) { + return cross(v, null); + } + + + /** + * Perform cross product between this and another vector, and store the + * result in 'target'. If target is null, a new vector is created. + */ + public PVector cross(PVector v, PVector target) { float crossX = y * v.z - v.y * z; float crossY = z * v.x - v.z * x; float crossZ = x * v.y - v.x * y; - return(new PVector(crossX,crossY,crossZ)); + + if (target == null) { + target = new PVector(crossX, crossY, crossZ); + } else { + target.set(crossX, crossY, crossZ); + } + return target; } + + + static public PVector cross(PVector v1, PVector v2, PVector target) { + float crossX = v1.y * v2.z - v2.y * v1.z; + float crossY = v1.z * v2.x - v2.z * v1.x; + float crossZ = v1.x * v2.y - v2.x * v1.y; + + if (target == null) { + target = new PVector(crossX, crossY, crossZ); + } else { + target.set(crossX, crossY, crossZ); + } + return target; + } + /** * Normalize the vector to length 1 (make it a unit vector) - */ + */ public void normalize() { - float m = magnitude(); + float m = mag(); if (m > 0) { div(m); } } + + + /** + * Normalize this vector, storing the result in another vector. + * @param target Set to null to create a new vector + * @return a new vector (if target was null), or target + */ + public PVector normalize(PVector target) { + if (target == null) { + target = new PVector(); + } + float m = mag(); + if (m > 0) { + target.set(x/m, y/m, z/m); + } else { + target.set(x, y, z); + } + return target; + } + /** * Limit the magnitude of this vector * @param max the maximum length to limit this vector - */ + */ public void limit(float max) { - if (magnitude() > max) { + if (mag() > max) { normalize(); mult(max); } } + /** * Calculate the angle of rotation for this vector (only 2D vectors) * @return the angle of rotation @@ -245,76 +489,18 @@ public class PVector { return -1*angle; } - /** - * Add two vectors - * @param v1 a vector - * @param v2 another vector - * @return a new vector that is the sum of v1 and v2 - */ - public static PVector add(PVector v1, PVector v2) { - PVector v = new PVector(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z); - return v; - } - - /** - * Subtract one vector from another - * @param v1 a vector - * @param v2 another vector - * @return a new vector that is v1 - v2 - */ - public static PVector sub(PVector v1, PVector v2) { - PVector v = new PVector(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z); - return v; - } - - /** - * Divide a vector by a scalar - * @param v1 a vector - * @param n scalar - * @return a new vector that is v1 / n - */ - public static PVector div(PVector v1, float n) { - PVector v = new PVector(v1.x/n,v1.y/n,v1.z/n); - return v; - } - - /** - * Multiply a vector by a scalar - * @param v1 a vector - * @param n scalar - * @return a new vector that is v1 * n - */ - public static PVector mult(PVector v1, float n) { - PVector v = new PVector(v1.x*n,v1.y*n,v1.z*n); - return v; - } - - - /** - * Calculate the Euclidean distance between two points (considering a point as a vector object) - * @param v1 a vector - * @param v2 another vector - * @return the Euclidean distance between v1 and v2 - */ - public static float distance (PVector v1, PVector v2) { - float dx = v1.x - v2.x; - float dy = v1.y - v2.y; - float dz = v1.z - v2.z; - return (float) Math.sqrt(dx*dx + dy*dy + dz*dz); - } - + /** * Calculate the angle between two vectors, using the dot product - * @param v1 a vector + * @param v1 a vector * @param v2 another vector * @return the angle between the vectors */ - public static float angleBetween(PVector v1, PVector v2) { + static public float angleBetween(PVector v1, PVector v2) { float dot = v1.dot(v2); - float theta = (float) Math.acos(dot / (v1.magnitude() * v2.magnitude())); + float theta = (float) Math.acos(dot / (v1.mag() * v2.mag())); return theta; } - }