Source: math/geo2d/WKcVector2D.js

/**
 * @author    Wolfgang Kowarschick
 * @copyright 2012-2013, Wolfgang Kowarschick
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted under the terms of the 
 * Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported    
 * (CC BY-NC-SA 3.0: http://creativecommons.org/licenses/by-nc-sa/3.0/). 
 */

////////////////////////////////////////////////////////////////////////////////
// Class "$wk$.math.geo2d.WKcVector2D"
////////////////////////////////////////////////////////////////////////////////

(function(pkg)
{ "use strict";  

  pkg("$wk$.math.geo2d");

  // Import.
  var WKcClass     = $wk$.WKcClass;
  var f_merge_into = WKcClass.mergeInto;
  var WKcMath      = $wk$.math.WKcMath;
  var WKtVector2D  = $wk$.math.geo2d.WKtVector2D;
  
  /**
   *  @param  {WKcVector2D|{min: WKcVector2D, max: WKcVector2D}} p_interval
   *          A single vector, an object with two vectors defining an interval,
   *          for each element, or an array of such values.
   *  @returns {WKcVector2D} 
   *          A random vector out of the values described by 
   *          <code>p_interval</code>.
   */ 
  WKcMath.randomVector2D =
    function(p_interval)
    { if (p_interval == null)
        new WKcVector2D;
      if (p_interval instanceof Array)
        p_interval = p_interval[Math.floor(Math.random()*p_interval.length)];
      if (p_interval instanceof Object && p_interval.min && p_interval.max)
      { var l_0 = p_interval.min, l_1 = p_interval.max;
        return new WKcVector2D(WKcMath.random({min: l_0.x, max: l_1.x}),
                               WKcMath.random({min: l_0.y, max: l_1.y})
                              );
      }
      else
        return new WKcVector2D(p_interval.x, p_interval.y);    
    };

  //============================================================================
  // Constructor
  //============================================================================
 
  /** 
   * @constructor
   * 
   * Creates a new vector and initializes it.
   * 
   * @param {Number} [p_x = 0]  The x-coordinate of the new vector.
   * @param {Number} [p_y = 0]  The y-coordinate of the new vector.
   */
  function WKcVector2D(p_x, p_y)
  { this.v_x = p_x || 0.0;
    this.v_y = p_y || 0.0;
    this.v_cache = [];
  };

  //============================================================================
  // Private Methods
  //============================================================================

  // Deletes all cached attribute values.
  function m_clear_cache() 
  { // Clear the cache, if it has not already been cleared. 
    if (this.v_cache.length)
      this.v_cache = [];
  };
 
  //============================================================================
  // Public Methods
  //============================================================================

  var l_prototype = WKcVector2D.prototype = 
  { constructor: WKcVector2D,

    //--------------------------------------------------------------------------
    // Cloning
    //--------------------------------------------------------------------------
    
    /**
     * Clones <code>this</code> vector and returns a modifyable vector.
     *  
     * <p>The return types of <code>WKtVector2D.clone</code> and 
     *    <code>WKcVector2D.clone</code> differ: The first method returns
     *    a <code>WKtVector2D<code> object, the second method returns a
     *    <code>WKcVector2D<code> object.  
     * </p>
     * 
     * @returns {WKcVector2D}  A <code>WKtVector2D</code> 
     *                         clone of <code>this</code> vector.
     */
    clone: 
      function(){ return new WKcVector2D(this.v_x, this.v_y); },

    /**
     * Clones <code>this</code> vector, but returns a non-modifyable vector. 
     *
     * <p>The return type of <code>WKtVector2D.clone</code> and 
     *    <code>WKcVector2D.clone</code> are identical: Both methods return
     *    a <code>WKtVector2D<code> object.  
     * </p>
     * 
     * @returns {WKtVector2D}  A <code>WKtVector2D</code> 
     *                        clone of <code>this</code> vector.
     */
    cloneN: 
      function(){ return new WKtVector2D(this.v_x, this.v_y); },

    /**
     * Clones <code>this</code> vector and returns a modifyable Vector.
     * 
     * <p>The return type of <code>WKtVector2D.clone</code> and 
     *    <code>WKcVector2D.clone</code> are identical: Both methods return
     *    a <code>WKcVector2D<code> object.  
     * </p>
     * 
     * @returns {WKcVector2D}  A <code>WKcVector2D</code> 
     *                         clone of <code>this</code> vector.
     */
    cloneM: 
      function(){ return new WKcVector2D(this.v_x, this.v_y); },
      
  };
  
  f_merge_into(l_prototype, WKtVector2D.prototype);

  f_merge_into
  (l_prototype,
  { //--------------------------------------------------------------------------
    // Attributes
    //--------------------------------------------------------------------------
    
    /** The x-coordinate ({Number}) of <code>this</code> vector. */
    set x(p_x) { if (this.v_x != p_x)
                 { this.v_x = p_x; 
                   m_clear_cache.call(this);
                 }
               },

    /** The y-coordinate ({Number}) of <code>this</code> vector. */
    set y(p_y) { if (this.v_y != p_y)
                 { this.v_y = p_y; 
                   m_clear_cache.call(this);
                 }
               },
    
    /** The length r ({Number}) of <code>this</code> vector. */
    set r(p_r) { if (this.r != p_r)
                 { var l_φ = this.φ;
                   this.v_x = p_r*Math.cos(l_φ); // this.φ has changed now!!
                   this.v_y = p_r*Math.sin(l_φ); // So here we must use l_φ!
                   m_clear_cache.call(this);
                 };
               },

    set length(p_length) { this.r = p_length; },
    /** The angle φ ({Number}) of <code>this</code> vector */
    set φ(p_φ) { if (this.φ != p_φ)
                 { var l_r = this.r;
                   this.v_x = l_r*Math.cos(p_φ); // this.r has changed now!!
                   this.v_y = l_r*Math.sin(p_φ); // So here we must use l_r!
                   m_clear_cache.call(this);
                 };
               },

    /**
     * Sets both cartesian coordinate attributes 
     * <code>x</code> and <code>y</code>
     * of <code>this</code> vector simultaneously. 
     * 
     * @param {Number} p_x  The x-coordinate of <code>this</code> vector.
     * @param {Number} p_y  The y-coordinate of <code>this</code> vector.
     */
    setXY: 
      function(p_x, p_y)
      { if (this.v_x != p_x && this.v_y != p_y)
        { this.v_x = p_x; 
          this.v_y = p_y; 
          m_clear_cache.call(this);
        };
        return this;
      },                   

    /**
     * Sets both polar coordinate attributes 
     * <code>r</code> and <code>φ</code>
     * of <code>this</code> vector simultaneously. 
     * 
     * @param {Number} p_r  The length of <code>this</code> vector.
     * @param {Number} p_φ  The angle (w.r.t the x-axis) 
     *                      of <code>this</code> vector.
     */
    setRΘ:
      function(p_r, p_φ)
      { if (this.r != p_r && this.v_φ != p_φ)
        { this.v_x = p_r*Math.cos(p_φ);
          this.v_y = p_r*Math.sin(p_φ);
          m_clear_cache.call(this);
        };
        return this;
      },

    //--------------------------------------------------------------------------
    // Update Methods
    //--------------------------------------------------------------------------

    /**
     * Replaces the coordinates of <code>this</code> vector
     * by the coordinates of another vector <code>p_v</code>.
     *
     * @param {WKcVector2D} p_v  The other vector.
     * 
     * @returns {WKcVector2D} <code>this</code>
     */
    replace: 
      function(p_v) 
      { this.v_x = p_v.x; 
        this.v_y = p_v.y;
        m_clear_cache.call(this);
        return this; 
      },

    /**
     * Modifies <code>this</code> vector by adding another vector 
     * <code>p_v</code> multiplied by a scalar factor to it.
     *
     * @param {WKcVector2D} p_v     The vector to be added.
     * @param {Number}      [p_s=1] The scalar factor.
     * 
     * @returns {WKcVector2D} <code>this</code>
     */
    addReplace:
      function(p_v, p_s) 
      { if (p_s != null)
        { this.v_x += p_s*p_v.x; this.v_y += p_s*p_v.y; }
        else
        { this.v_x += p_v.x;     this.v_y += p_v.y;     };
        m_clear_cache.call(this);
        return this; 
      }, 
    
    /**
     * Modifies <code>this</code> vector by subtracting another vector
     * <code>p_v</code> multiplied by a scalar factor from it.
     *
     * @param {WKcVector2D} p_v     The vector to be added.
     * @param {Number}      [p_s=1] The scalar factor.
     * 
     * @returns {WKcVector2D} <code>this</code>
     */
    subReplace:
      function(p_v, p_s) 
      { if (p_s != null)
        { this.v_x -= p_s*p_v.x; this.v_y -= p_s*p_v.y; }
        else
        { this.v_x -= p_v.x;     this.v_y -= p_v.y;     }; 
        m_clear_cache.call(this);
        return this; 
      }, 

    /**
     * Modifies <code>this</code> vector by multiplying it with a scalar value.
     *
     * @param {Number} p_s  The scalar value.
     * 
     * @returns {WKcVector2D} <code>this</code>
     */
    scaleReplace:
      function(p_s) 
      { this.v_x *= p_s; 
        this.v_y *= p_s; 
        m_clear_cache.call(this);
        return this; 
      }, 

    /**
     * Modifies <code>this</code> vector by normalizing it.
     *
     * @returns {WKcVector2D} <code>this</code>
     */
    unitReplace:
      function() 
      { var l_r = this.r;
      
        if (l_r == 0)
          return this;
        else
        { this.v_cache.m_get_is_unit = true;
          return this.scaleReplace(1/l_r);
        }
      },
    
    /**
     * Replaces <code>this</code> vector by a vector that is rotated 
     * 90 degrees counterclockwise. The length is preserved.
     *
     * @returns {WKcVector2D} <code>this</code>
     */
    normalReplace:
      function() 
      { var l_x = this.x;
        this.v_x = -this.y;
        this.v_y = l_x;
        m_clear_cache.call(this);
        return this;
      }, 

    /**
     * Replaces <code>this</code> vector by a projection of 
     * <code>this</code> vector onto another vector <code>p_v</code>.
     *
     * @param {WKcVector2D} p_v  The vector onto which <code>this</code> vector
     *                           is projected.
     * @precondition <code>!p_v.isZero()</code>
     *
     * @returns {WKcVector2D} <code>this</code>, which now is 
     *                       a multiple of <code>p_v</code>.
     */
    projReplace:
      function(p_v) 
      { if (p_v.isUnit)
          this.replace(p_v.scale(this.dot(p_v)));
        else
          this.replace(p_v.scale(this.dot(p_v)/p_v.rSqr));
      }, 

    /**
     * Replaces <code>this</code> vector by the reflection vector 
     * that arises from <code>this</code> vector being reflected by a 
     * "mirror" vector <code>v_m</code>.
     * The length of the reflection vector is the same as the length of 
     * <code>this</code> vector multiplied by a scalar factor. 
     *
     * @param {WKcVector2D} p_m     The mirror vector.
     * @param {Number}      [p_s=1] The scalar factor.
     * 
     * @precondition <code>!p_m.isZero()</code>
     *
     * @returns {WKcVector2D} <code>this</code>
     */
    reflectReplace:
      function(p_m, p_s) 
      { p_s = p_s || 1;
        var l_n = p_m.normal();
        if (l_n.isUnit) 
          this.subReplace(l_n.scale(2*p_s*this.dot(l_n)));
        else
          this.subReplace(l_n.scale(2*p_s*this.dot(l_n)/l_n.rSqr));
      }, 
  }
  );

  //============================================================================
  // End of Member Definitions
  //============================================================================

  // Export the class definition.
  $wk$.math.geo2d.WKcVector2D = WKcVector2D;
})($wk$.pkg);

////////////////////////////////////////////////////////////////////////////////
// End of Class Definition
////////////////////////////////////////////////////////////////////////////////
W. Kowarschick © 2013 (CC BY-NC-SA 3.0: http://creativecommons.org/licenses/by-nc-sa/3.0/)
Documentation generated by JSDoc 3.3.0-dev on Sat Oct 05 2013 15:14:39 GMT+0200 (MESZ) using the DocStrap template.