Actionscript Vector Class

by Jim Jun 12, 2007 5:23 PM

I've been working on some stuff lately that requires vector manipulation in ActionScript. Specifically I need to hit test lines to see if the mouse has been clicked near them. This class provides a function for that and some other basic vector operations.

package Utils
{
    import flash.geom.Point;
    
    // Derived from and converted from code at:
    // http://msdn2.microsoft.com/en-us/library/ms969920.aspx

    // Defines a Vector object and various associated functions
    public class Vector
    {
        public var x:Number;
        public var y:Number;
 
        public function Vector(xValue:Number = 0, yValue:Number = 0)
        {
            x = xValue;
            y = yValue;
        }

        // Get the magnitude of this vector
        public function get magnitude():Number
        {
            return Math.sqrt(x * x + y * y);
        }

        // Subtract the given vector from this one
        public function subtract(v1:Vector):Vector
        {
            return new Vector(x - v1.x, y - v1.y);
        }

        // Get a dot product with the passed in vector
        public function dot(v1:Vector):Number
        {
            return (x * v1.x) + (y * v1.y);
        }

        // Multiple the vector by the given scalar number
        public function times(m:Number):Vector
        {
            return new Vector(x * m, y * m);
        }

        public function toString():String
        {
            return "Vector (" + x.toString() + ", " + y.toString() + ")";
        }

        /* ********************** Static functions **************************** */

        // Create a new vector defined by the given points
        public static function pointsToVector(pt0:Point, pt1:Point):Vector
        {
            return new Vector(pt1.x - pt0.x, pt1.y - pt0.y);
        }

        public static function hitTestLine(
            pt0:Point, pt1:Point, ptMouse:Point, width:Number):Boolean
        {
            var tt0:Vector;
            var tt1:Vector;
            var dist:Number;
            var nHalfWidth:int;
            
            // Get the half width of the line to adjust for hit testing of wide lines.
            nHalfWidth = (width / 2 < 1) ? 1 : width / 2;
            
            // Convert the line into a vector using the two endpoints.
            tt0 = Vector.pointsToVector(pt0, pt1);

            // Convert the line from the left endpoint to the mouse point into a vector.
            tt1 = Vector.pointsToVector(pt0, ptMouse);

            // Get the distance of the point from the line.
            dist = getLengthOfNormal(tt1, tt0);
       
            // Return true if we're within the width of the line
            return (dist >= -nHalfWidth && dist <= nHalfWidth);
        }

        // Get the projection of the given vector onto this one
        public function projectionOf(a:Vector):Vector
        {
            // c = ((a * b)/(|b|^2))*b
            return this.times(a.dot(this) / this.dot(this));
        }

        // Get length of the normal vector between the endpoint of vector a and vector b
        public static function getLengthOfNormal(a:Vector, b:Vector):Number
        {
            var c:Vector;
            var vNormal:Vector;

            c = b.projectionOf(a);

            // Obtain perpendicular projection : e = a - c
            vNormal = a.subtract(c);
            
            return vNormal.magnitude;
        }

    }
}

Tags: