text: /**
   * A helper class to facilitate common operations on points and vectors.
   */
  Ext.define('Ext.draw.Point', {
  
      requires: [
          'Ext.draw.Draw',
          'Ext.draw.Matrix'
      ],
  
      isPoint: true,
  
      x: 0,
      y: 0,
  
      length: 0,
      angle: 0,
  
      angleUnits: 'degrees',
  
      statics: {
          /**
           * @method
           * @static
           * Creates a flyweight Ext.draw.Point instance.
           * Takes the same parameters as the {@link Ext.draw.Point#constructor}.
           * Do not hold the instance of the flyweight point.
           *
           * @param {Number/Number[]/Object/Ext.draw.Point} point
           * @return {Ext.draw.Point}
           */
          fly: (function () {
              var point = null;
              return function (x, y) {
                  if (!point) {
                      point = new Ext.draw.Point();
                  }
                  point.constructor(x, y);
                  return point;
              }
          })()
      },
  
      /**
       * Creates a point.
       *
       *     new Ext.draw.Point(3, 4);
       *     new Ext.draw.Point(3); // both x and y equal 3
       *     new Ext.draw.Point([3, 4]);
       *     new Ext.draw.Point({x: 3, y: 4});
       *     new Ext.draw.Point(p); // where `p` is a Ext.draw.Point instance.
       *
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       */
      constructor: function (x, y) {
          var me = this;
  
          if (typeof x === 'number') {
              me.x = x;
              if (typeof y === 'number') {
                  me.y = y;
              } else {
                  me.y = x;
              }
          } else if (Ext.isArray(x)) {
              me.x = x[0];
              me.y = x[1];
          } else if (x) {
              me.x = x.x;
              me.y = x.y;
          }
  
          me.calculatePolar();
      },
  
      calculateCartesian: function () {
          var me = this,
              length = me.length,
              angle = me.angle;
  
          if (me.angleUnits === 'degrees') {
              angle = Ext.draw.Draw.rad(angle);
          }
          me.x = Math.cos(angle) * length;
          me.y = Math.sin(angle) * length;
      },
  
      calculatePolar: function () {
          var me = this,
              x = me.x,
              y = me.y;
  
          me.length = Math.sqrt(x * x + y * y);
          me.angle = Math.atan2(y, x);
          if (me.angleUnits === 'degrees') {
              me.angle = Ext.draw.Draw.degrees(me.angle);
          }
      },
  
      /**
       * Sets the x-coordinate of the point.
       * @param {Number} x
       */
      setX: function (x) {
          this.x = x;
          this.calculatePolar();
      },
  
      /**
       * Sets the y-coordinate of the point.
       * @param {Number} y
       */
      setY: function (y) {
          this.y = y;
          this.calculatePolar();
      },
  
      /**
       * Sets coordinates of the point.
       * Takes the same parameters as the {@link #constructor}.
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       */
      set: function (x, y) {
          this.constructor(x, y);
      },
  
      /**
       * Sets the angle of the vector (measured from the x-axis to the vector)
       * without changing its length.
       * @param {Number} angle
       */
      setAngle: function (angle) {
          this.angle = angle;
          this.calculateCartesian();
      },
  
      /**
       * Sets the length of the vector without changing its angle.
       * @param {Number} length
       */
      setLength: function (length) {
          this.length = length;
          this.calculateCartesian();
      },
  
      /**
       * Sets both the angle and the length of the vector.
       * A point can be thought of as a vector pointing from the origin to the point's location.
       * This can also be interpreted as setting coordinates of a point in the polar
       * coordinate system.
       * @param {Number} angle
       * @param {Number} length
       */
      setPolar: function (angle, length) {
          this.angle = angle;
          this.length = length;
          this.calculateCartesian();
      },
  
      /**
       * Returns a copy of the point.
       * @return {Ext.draw.Point}
       */
      clone: function () {
          return new Ext.draw.Point(this.x, this.y);
      },
  
      /**
       * Adds another vector to this one and returns the resulting vector
       * without changing this vector.
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       * @return {Ext.draw.Point}
       */
      add: function (x, y) {
          var fly = Ext.draw.Point.fly(x, y);
          return new Ext.draw.Point(this.x + fly.x, this.y + fly.y);
      },
  
      /**
       * Subtracts another vector from this one and returns the resulting vector
       * without changing this vector.
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       * @return {Ext.draw.Point}
       */
      sub: function (x, y) {
          var fly = Ext.draw.Point.fly(x, y);
          return new Ext.draw.Point(this.x - fly.x, this.y - fly.y);
      },
  
      /**
       * Returns the result of scalar multiplication of this vector by the given factor.
       * This vector is not modified.
       * @param {Number} n The factor.
       * @return {Ext.draw.Point}
       */
      mul: function (n) {
          return new Ext.draw.Point(this.x * n, this.y * n);
      },
  
      /**
       * Returns a vector which coordinates are the result of division of this vector's
       * coordinates by the given number. This vector is not modified.
       * This vector is not modified.
       * @param {Number} n The denominator.
       * @return {Ext.draw.Point}
       */
      div: function (n) {
          return new Ext.draw.Point(this.x / n, this.y / n);
      },
  
      /**
       * Returns the dot product of this vector and the given vector.
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       * @return {Number}
       */
      dot: function (x, y) {
          var fly = Ext.draw.Point.fly(x, y);
          return this.x * fly.x + this.y * fly.y;
      },
  
      /**
       * Checks whether coordinates of the point match those of the point provided.
       * @param {Number/Number[]/Object/Ext.draw.Point} x
       * @param {Number/Number[]/Object/Ext.draw.Point} y
       * @return {Boolean}
       */
      equals: function (x, y) {
          var fly = Ext.draw.Point.fly(x, y);
          return this.x === fly.x && this.y === fly.y;
      },
  
      /**
       * Rotates the point by the given angle. This point is not modified.
       * @param {Number} angle The rotation angle.
       * @param {Ext.draw.Point} center The center of rotation (optional). Defaults to origin.
       * @return {Ext.draw.Point} The rotated point.
       */
      rotate: function (angle, center) {
          var sin, cos,
              cx, cy,
              point;
  
          if (this.angleUnits === 'degrees') {
              angle = Ext.draw.Draw.rad(angle);
              sin = Math.sin(angle);
              cos = Math.cos(angle);
          }
          if (center) {
              cx = center.x;
              cy = center.y;
          } else {
              cx = 0;
              cy = 0;
          }
          point = Ext.draw.Matrix.fly([
              cos, sin,
              -sin, cos,
              cx - cos * cx + cy * sin,
              cy - cos * cy + cx * -sin
          ]).transformPoint(this);
  
          return new Ext.draw.Point(point);
      },
  
      /**
       * Transforms the point from one coordinate system to another
       * using the transformation matrix provided. This point is not modified.
       * @param {Ext.draw.Matrix/Number[]} matrix A trasformation matrix or its elements.
       * @return {Ext.draw.Point}
       */
      transform: function (matrix) {
          if (matrix && matrix.isMatrix) {
              return new Ext.draw.Point(matrix.transformPoint(this));
          } else if (arguments.length === 6) {
              return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this));
          } else {
              Ext.raise("Invalid parameters.");
          }
      },
  
      /**
       * Returns a new point with rounded x and y values. This point is not modified.
       * @return {Ext.draw.Point}
       */
      round: function () {
          return new Ext.draw.Point(
              Math.round(this.x),
              Math.round(this.y)
          );
      },
  
      /**
       * Returns a new point with ceiled x and y values. This point is not modified.
       * @return {Ext.draw.Point}
       */
      ceil: function () {
          return new Ext.draw.Point(
              Math.ceil(this.x),
              Math.ceil(this.y)
          );
      },
  
      /**
       * Returns a new point with floored x and y values. This point is not modified.
       * @return {Ext.draw.Point}
       */
      floor: function () {
          return new Ext.draw.Point(
              Math.floor(this.x),
              Math.floor(this.y)
          );
      },
  
      /**
       * Returns a new point with absolute values of the x and y values of this point.
       * This point is not modified.
       * @return {Ext.draw.Point}
       */
      abs: function (x, y) {
          return new Ext.draw.Point(
              Math.abs(this.x),
              Math.abs(this.y)
          );
      },
  
      /**
       * Normalizes the vector by changing its length to 1 without changing its angle.
       * The returned result is a normalized vector. This vector is not modified.
       * @param {Number} [factor=1] Multiplication factor. Defaults to 1.
       * @return {Ext.draw.Point}
       */
      normalize: function (factor) {
          var x = this.x,
              y = this.y,
              k = (factor || 1) / Math.sqrt(x*x + y*y);
  
          return new Ext.draw.Point(x * k, y * k);
      },
  
      /**
       * Returns the vector from the point perpendicular to the line (shortest distance).
       * Where line is specified using two points or the coordinates of those points.
       * @param {Ext.draw.Point} p1
       * @param {Ext.draw.Point} p2
       * @return {Ext.draw.Point}
       */
      getDistanceToLine: function (p1, p2) {
          if (arguments.length === 4) {
              p1 = new Ext.draw.Point(arguments[0], arguments[1]);
              p2 = new Ext.draw.Point(arguments[2], arguments[3]);
          }
          // See http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Vector_formulation
          var n = p2.sub(p1).normalize(),
              pp1 = p1.sub(this);
          return pp1.sub(n.mul(pp1.dot(n)));
      },
  
      /**
       * Checks if both x and y coordinates of the point are zero.
       * @return {Boolean}
       */
      isZero: function () {
          return this.x === 0 && this.y === 0;
      },
  
      /**
       * Checks if both x and y coordinates of the point are valid numbers.
       * @return {Boolean}
       */
      isNumber: function () {
          return Ext.isNumber(this.x) && Ext.isNumber(this.y);
      }
  
  });