text: // Copyright 2006 The Closure Library Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  /**
   * @fileoverview A utility class for representing a numeric box.
   */
  
  
  goog.provide('goog.math.Box');
  
  goog.require('goog.math.Coordinate');
  
  
  
  /**
   * Class for representing a box. A box is specified as a top, right, bottom,
   * and left. A box is useful for representing margins and padding.
   *
   * @param {number} top Top.
   * @param {number} right Right.
   * @param {number} bottom Bottom.
   * @param {number} left Left.
   * @constructor
   */
  goog.math.Box = function(top, right, bottom, left) {
    /**
     * Top
     * @type {number}
     */
    this.top = top;
  
    /**
     * Right
     * @type {number}
     */
    this.right = right;
  
    /**
     * Bottom
     * @type {number}
     */
    this.bottom = bottom;
  
    /**
     * Left
     * @type {number}
     */
    this.left = left;
  };
  
  
  /**
   * Creates a Box by bounding a collection of goog.math.Coordinate objects
   * @param {...goog.math.Coordinate} var_args Coordinates to be included inside
   *     the box.
   * @return {!goog.math.Box} A Box containing all the specified Coordinates.
   */
  goog.math.Box.boundingBox = function(var_args) {
    var box = new goog.math.Box(arguments[0].y, arguments[0].x,
                                arguments[0].y, arguments[0].x);
    for (var i = 1; i < arguments.length; i++) {
      var coord = arguments[i];
      box.top = Math.min(box.top, coord.y);
      box.right = Math.max(box.right, coord.x);
      box.bottom = Math.max(box.bottom, coord.y);
      box.left = Math.min(box.left, coord.x);
    }
    return box;
  };
  
  
  /**
   * Creates a copy of the box with the same dimensions.
   * @return {!goog.math.Box} A clone of this Box.
   */
  goog.math.Box.prototype.clone = function() {
    return new goog.math.Box(this.top, this.right, this.bottom, this.left);
  };
  
  
  if (goog.DEBUG) {
    /**
     * Returns a nice string representing the box.
     * @return {string} In the form (50t, 73r, 24b, 13l).
     */
    goog.math.Box.prototype.toString = function() {
      return '(' + this.top + 't, ' + this.right + 'r, ' + this.bottom + 'b, ' +
             this.left + 'l)';
    };
  }
  
  
  /**
   * Returns whether the box contains a coordinate or another box.
   *
   * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box.
   * @return {boolean} Whether the box contains the coordinate or other box.
   */
  goog.math.Box.prototype.contains = function(other) {
    return goog.math.Box.contains(this, other);
  };
  
  
  /**
   * Expands box with the given margins.
   *
   * @param {number|goog.math.Box} top Top margin or box with all margins.
   * @param {number=} opt_right Right margin.
   * @param {number=} opt_bottom Bottom margin.
   * @param {number=} opt_left Left margin.
   * @return {!goog.math.Box} A reference to this Box.
   */
  goog.math.Box.prototype.expand = function(top, opt_right, opt_bottom,
      opt_left) {
    if (goog.isObject(top)) {
      this.top -= top.top;
      this.right += top.right;
      this.bottom += top.bottom;
      this.left -= top.left;
    } else {
      this.top -= top;
      this.right += opt_right;
      this.bottom += opt_bottom;
      this.left -= opt_left;
    }
  
    return this;
  };
  
  
  /**
   * Expand this box to include another box.
   * NOTE(user): This is used in code that needs to be very fast, please don't
   * add functionality to this function at the expense of speed (variable
   * arguments, accepting multiple argument types, etc).
   * @param {goog.math.Box} box The box to include in this one.
   */
  goog.math.Box.prototype.expandToInclude = function(box) {
    this.left = Math.min(this.left, box.left);
    this.top = Math.min(this.top, box.top);
    this.right = Math.max(this.right, box.right);
    this.bottom = Math.max(this.bottom, box.bottom);
  };
  
  
  /**
   * Compares boxes for equality.
   * @param {goog.math.Box} a A Box.
   * @param {goog.math.Box} b A Box.
   * @return {boolean} True iff the boxes are equal, or if both are null.
   */
  goog.math.Box.equals = function(a, b) {
    if (a == b) {
      return true;
    }
    if (!a || !b) {
      return false;
    }
    return a.top == b.top && a.right == b.right &&
           a.bottom == b.bottom && a.left == b.left;
  };
  
  
  /**
   * Returns whether a box contains a coordinate or another box.
   *
   * @param {goog.math.Box} box A Box.
   * @param {goog.math.Coordinate|goog.math.Box} other A Coordinate or a Box.
   * @return {boolean} Whether the box contains the coordinate or other box.
   */
  goog.math.Box.contains = function(box, other) {
    if (!box || !other) {
      return false;
    }
  
    if (other instanceof goog.math.Box) {
      return other.left >= box.left && other.right <= box.right &&
          other.top >= box.top && other.bottom <= box.bottom;
    }
  
    // other is a Coordinate.
    return other.x >= box.left && other.x <= box.right &&
           other.y >= box.top && other.y <= box.bottom;
  };
  
  
  /**
   * Returns the distance between a coordinate and the nearest corner/side of a
   * box. Returns zero if the coordinate is inside the box.
   *
   * @param {goog.math.Box} box A Box.
   * @param {goog.math.Coordinate} coord A Coordinate.
   * @return {number} The distance between {@code coord} and the nearest
   *     corner/side of {@code box}, or zero if {@code coord} is inside
   *     {@code box}.
   */
  goog.math.Box.distance = function(box, coord) {
    if (coord.x >= box.left && coord.x <= box.right) {
      if (coord.y >= box.top && coord.y <= box.bottom) {
        return 0;
      }
      return coord.y < box.top ? box.top - coord.y : coord.y - box.bottom;
    }
  
    if (coord.y >= box.top && coord.y <= box.bottom) {
      return coord.x < box.left ? box.left - coord.x : coord.x - box.right;
    }
  
    return goog.math.Coordinate.distance(coord,
        new goog.math.Coordinate(coord.x < box.left ? box.left : box.right,
                                 coord.y < box.top ? box.top : box.bottom));
  };
  
  
  /**
   * Returns whether two boxes intersect.
   *
   * @param {goog.math.Box} a A Box.
   * @param {goog.math.Box} b A second Box.
   * @return {boolean} Whether the boxes intersect.
   */
  goog.math.Box.intersects = function(a, b) {
    return (a.left <= b.right && b.left <= a.right &&
            a.top <= b.bottom && b.top <= a.bottom);
  };
  
  
  /**
   * Returns whether two boxes would intersect with additional padding.
   *
   * @param {goog.math.Box} a A Box.
   * @param {goog.math.Box} b A second Box.
   * @param {number} padding The additional padding.
   * @return {boolean} Whether the boxes intersect.
   */
  goog.math.Box.intersectsWithPadding = function(a, b, padding) {
    return (a.left <= b.right + padding && b.left <= a.right + padding &&
            a.top <= b.bottom + padding && b.top <= a.bottom + padding);
  };
  