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 + ")";
}
}
}