package com.robertpenner.geom { import com.robertpenner.utils.Degree; import flash.geom.Point; /** * The Vector class is designed to represent vectors and points * in two-dimensional space. Vectors can be added together, * scaled, rotated, and otherwise manipulated with these methods. * * @author Robert Penner ( AS 1.0 ) * © 2002 Robert Penner * http://www.robertpenner.com * * @author Mark Walters ( AS 2.0 and AS 3.0 ) * © 2007 DigitalFlipbook * http://www.digitalflipbook.com * * @langversion ActionScript 3.0 * @playerversion Flash 9 */ public class Vector { //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * Adds the coordinates of one vector to the coordinates of another vector to create a new vector. * * @param v1 The first vector. * @param v2 The second vector that is added to the first vector. * * @return The new vector. * * @example * <listing> * var position:Vector = new Vector( 4, 1 ); * var velocity:Vector = new Vector( -2, 0 ); * var newPosition:Vector = Vector.add( position, velocity ); * trace( newPosition ); * </listing> */ public static function add( v1:Vector, v2:Vector ):Vector { return new Vector( v1.x + v2.x, v1.y + v2.y ); } /** * Subtracts the coordinates of one vector from the coordinates of another vector to create a new vector. * * @param v1 The first vector. * @param v2 The second vector that is subtracted from the first vector. * * @return The new vector. * * @example * <listing> * var pointA:Vector = new Vector( 0, 1 ); * var pointB:Vector = new Vector( -2, 0 ); * var displacement:Vector = Vector.subtract( pointB, pointA ); * trace( displacement ); * </listing> */ public static function subtract( v1:Vector, v2:Vector ):Vector { return new Vector( v1.x - v2.x, v1.y - v2.y ); } /** * Reverses the direction of a vector and returns the result as a new vector. * * @param v The vector to reverse. * * @return The reversed vector. * * @example * <listing> * var forward:Vector = new Vector( 99, 0 ); * var backward:Vector = Vector.reverse( forward ); * trace( backward ); * </listing> */ public static function reverse( v:Vector ):Vector { return new Vector( -v.x, -v.y ); } /** * Scales the length of a vector by a scale factor and returns the result of the scale as a new vector. * * @param v The vector to scale. * @param s The scale factor to multiply the vector by. * * @return The scaled vector. * * @example * <listing> * var windForce:Vector = new Vector( -2, 1 ); * var galeForce:Vector = Vector.scale( windForce, 2 ); //strong wind * trace( galeForce ); * </listing> */ public static function scale( v:Vector, s:Number ):Vector { return new Vector( v.x * s, v.y * s ); } /** * Rotates the angle of a vector by a certain amount of degrees and returns the result of the rotation as a new vector. * * @param v The vector to rotate. * @param ang The amount of degrees that the vector will be rotated by. * * @return The rotated vector. * * @example * <listing> * var direction:Vector = new Vector( 5, 5 ); * var newDirection:Vector = Vector.rotate( direction, 10 ); * trace( newDirection.angle ); * </listing> */ public static function rotate( v:Vector, ang:Number ):Vector { var rv:Vector = new Vector( v.x, v.y ); rv.rotate( ang ); return rv; } /** * Returns the distance between two vectors. * * @param v1 The first vector. * @param v2 The second vector. * * @return The distance between the first vector and the second vector. * * @example * <listing> * var v1:Vector = new Vector( 10, 10 ); * var v2:Vector = new Vector( 20, 20 ); * var distance:Number = Vector.distance( v1, v2 ); * trace( distance ); * </listing> */ public static function distance( v1:Vector, v2:Vector ):Number { var dx:Number = v2.x - v1.x; var dy:Number = v2.y - v1.y; return Math.sqrt( dx*dx + dy*dy ); } /** * Returns the angle between two vectors. * * @param v1 The first vector. * @param v2 The second vector. * * @return The angle between the first vector and the second vector. * * @example * <listing> * var pullForce:Vector = new Vector( 4, 0 ); * var frictionForce:Vector = new Vector( -1, 0 ); * var theta:Number = Vector.angleBetween( pullForce, frictionForce ); * trace( theta ); * </listing> */ public static function angleBetween( v1:Vector, v2:Vector ):Number { var dp:Number = v1.dot( v2 ); var cosAngle:Number = dp / ( v1.length * v2.length ); return Degree.acosD( cosAngle ); } /** * Converts a point object to a vector. * * @param p The point to convert. * * @return The converted point as a vector. * * @example * <listing> * var p:Point = new Point( 4, 2 ); * var v:Vector = Vector.pointToVector( p ); * trace( v ); * </listing> */ public static function pointToVector( p:Point ):Vector { return new Vector( p.x, p.y ); } /** * Converts a vector object to a point. * * @param v The vector to convert. * * @return The converted vector as a point. * * @example * <listing> * var v:Vector = new Vector( 4, 2 ); * var p:Point = Vector.vectorToPoint( v ); * trace( p ); * </listing> */ public static function vectorToPoint( v:Vector ):Point { return new Point( v.x, v.y ); } //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @param x The x value of the vector. * @param y The y value of the vector. * * @example * <listing> * var v:Vector = new Vector( -9, 4 ); * trace( v.x ); * trace( v.y ); * </listing> */ public function Vector( x:Number=0, y:Number=0 ) { this.x = x; this.y = y; } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // x //---------------------------------- /** * @private * Storage for the x property. */ private var _x:Number; /** * The x property of the vector object. * * @example * <listing> * v.x = 9; * </listing> */ public function get x():Number { return _x; } /** * @private */ public function set x( x:Number ):void { _x = x; } //---------------------------------- // y //---------------------------------- /** * @private * Storage for the y property. */ private var _y:Number; /** * The y property of the vector object. * * @example * <listing> * v.y = -4; * </listing> */ public function get y():Number { return _y; } /** * @private */ public function set y( y:Number ):void { _y = y; } //---------------------------------- // length //---------------------------------- /** * The length (or magnitude) of the vector object. * * @example * <listing> * var velocity:Vector = new Vector( 3, 4 ); * var newSpeed:Number = 10; * velocity.length = newSpeed; * trace( velocity ); * trace( velocity.length ); * </listing> */ public function get length():Number { return Math.sqrt( x*x + y*y ); } /** * @private */ public function set length( len:Number ):void { var r:Number = length; r ? scale( len/r ) : x = len; } //---------------------------------- // angle //---------------------------------- /** * The angle of the vector object. * * @example * <listing> * var destination:Vector = new Vector( 5, 5 ); * var compassBearing:Number = destination.angle; * trace( compassBearing ); * </listing> */ public function get angle():Number { return Degree.atan2D( y, x ); } /** * @private */ public function set angle( ang:Number ):void { var r:Number = length; x = r * Degree.cosD( ang ); y = r * Degree.sinD( ang ); } //---------------------------------- // normal //---------------------------------- /** * Finds a normal for the current vector. * * @return Returns the vector that is the normal to the current vector. * * @example * <listing> * var wallDirection:Vector = new Vector( 3, 5 ); * var forceDirection:Vector = wallDirection.normal; * trace( forceDirection ); * </listing> */ public function get normal():Vector { return new Vector( -y, x ); } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Reinitializes the vector object. * * @param x The x value of the vector. * @param y The y value of the vector. * * @example * <listing> * var velocity:Vector = new Vector( 5, 1 ); * velocity.reset( -9, 7 ); * trace( velocity ); * </listing> */ public function reset( x:Number=0, y:Number=0 ):void { this.x = x; this.y = y; } /** * Returns a new vector object containing the x and y values of the current vector. * * @return A copy of the current vector object. * * @example * <listing> * var forceA:Vector = new Vector( 2, 4 ); * var forceB:Vector = forceA.clone(); * trace( forceA ); * trace( forceB ); * trace( forceA.equals( forceB ) ); * </listing> */ public function clone():Vector { return new Vector( x, y ); } /** * Determines whether two vectors are equal. * * @param v The vector to be compared. * * @return A value of <code>true</code> if the object is equal to this Vector object; <code>false</code> if it is not equal. * * @example * <listing> * var forceA:Vector = new Vector( 2, 4 ); * var forceB:Vector = forceA.clone(); * trace( forceB.equals( forceA ) ); * forceA.reset( 0, 0 ); * trace( forceB.equals( forceA ) ); * </listing> */ public function equals( v:Vector ):Boolean { return ( x == v.x && y == v.y ); } /** * Adds the coordinates of another vector to the coordinates of this vector. * * @param v The vector to be added. * * @example * <listing> * var position:Vector = new Vector( 1, 3 ); * var velocity:Vector = new Vector( 3, 0 ); * position.add( velocity ); * trace( position ); * </listing> */ public function add( v:Vector ):void { x += v.x; y += v.y; } /** * Subtracts the coordinates of another vector from the coordinates of this vector. * * @param v The vector to be subtracted. * * @example * <listing> * var forceA:Vector = new Vector( 1, 1 ); * var forceB:Vector = new Vector( -2, -1 ); * forceA.subtract( forceB ); * trace( forceA ); * </listing> */ public function subtract( v:Vector ):void { x -= v.x; y -= v.y; } /** * Reverses the direction of the current vector. * * @example * <listing> * var direction:Vector = new Vector( 2, 3 ); * direction.reverse(); * trace( direction ); * </listing> */ public function reverse():void { x = -x; y = -y; } /** * Scales the length of the current vector object by a scale factor. * * @param s The scale factor to multiply the current vector by. * * @example * <listing> * var windForce:Vector = new Vector( 2, 3 ); * windForce.scale( 2 ); * trace( windForce ); * </listing> */ public function scale( s:Number ):void { x *= s; y *= s; } /** * Rotates the angle of the current vector object by a certain amount of degrees. * * @param ang The amount of degrees that the current vector object will be rotated by. * * @example * <listing> * var direction:Vector = new Vector( 5, 5 ); * trace( direction.angle ); * direction.rotate( -90 ); * trace( direction ); * trace( direction.angle ); * </listing> */ public function rotate( ang:Number ):void { var ca:Number = Degree.cosD( ang ); var sa:Number = Degree.sinD( ang ); var rx:Number = x * ca - y * sa; var ry:Number = x * sa + y * ca; x = rx; y = ry; } /** * Calculates the dot product of the current vector with another vector. * * @param v The vector to multiply the current vector by. * * @return The dot product. * * @example * <listing> * var v1:Vector = new Vector( 2, 3 ); * var v2:Vector = new Vector( 4, 5 ); * trace( v1.dot( v2 ) ); * trace( v2.dot( v1 ) ); * </listing> */ public function dot( v:Vector ):Number { return x * v.x + y * v.y; } /** * Determines whether the current vector is the normal of (or perpendicular to) another vector. * * @param v The vector object to check perpendicularity against. * @return A value of <code>true</code> if the dot product is zero; <code>false</code> if it is not zero. * * @example * <listing> * var goingLeft:Vector = new Vector( -3, 0 ); * var goingRight:Vector = new Vector( 5, 0 ); * trace( goingLeft.isNormalTo( goingRight ) ); * var goingUp:Vector = new Vector( 0, 8 ); * trace( goingUp.isNormalTo( goingLeft ) ); * </listing> */ public function isNormalTo( v:Vector ):Boolean { return( dot( v ) == 0 ); } /** * Normalizes the current vector to a length (or magnitude) of 1. * Normalized vectors are sometimes referred to as unit vectors. * * @example * <listing> * var v:Vector = new Vector( 2, 3 ); * v.normalize(); * trace( v.length ); * </listing> */ public function normalize():void { var len:Number = length; if( len != 0 && len != 1) { x /= len; y /= len; } } /** * Returns a string representation of the vector object. * * @return The string representation of the vector object. * * @example * <listing> * var position:Vector = new Vector( 5, 8 ); * trace( position.toString() ); * trace( position ); * </listing> */ public function toString():String { var rx:Number = Math.round( x * 1000 ) / 1000; var ry:Number = Math.round( y * 1000 ) / 1000; return "(x=" + rx + ", y=" + ry + ")"; } } }