# lib/goog/math/coordinate.js

    1// Copyright 2006 The Closure Library Authors. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS-IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.1415/**16 * @fileoverview A utility class for representing two-dimensional positions.17 */181920goog.provide('goog.math.Coordinate');2122goog.require('goog.math');23242526/**27 * Class for representing coordinates and positions.28 * @param {number=} opt_x Left, defaults to 0.29 * @param {number=} opt_y Top, defaults to 0.30 * @constructor31 */32goog.math.Coordinate = function(opt_x, opt_y) {33  /**34   * X-value35   * @type {number}36   */37  this.x = goog.isDef(opt_x) ? opt_x : 0;3839  /**40   * Y-value41   * @type {number}42   */43  this.y = goog.isDef(opt_y) ? opt_y : 0;44};454647/**48 * Returns a new copy of the coordinate.49 * @return {!goog.math.Coordinate} A clone of this coordinate.50 */51goog.math.Coordinate.prototype.clone = function() {52  return new goog.math.Coordinate(this.x, this.y);53};545556if (goog.DEBUG) {57  /**58   * Returns a nice string representing the coordinate.59   * @return {string} In the form (50, 73).60   * @override61   */62  goog.math.Coordinate.prototype.toString = function() {63    return '(' + this.x + ', ' + this.y + ')';64  };65}666768/**69 * Compares coordinates for equality.70 * @param {goog.math.Coordinate} a A Coordinate.71 * @param {goog.math.Coordinate} b A Coordinate.72 * @return {boolean} True iff the coordinates are equal, or if both are null.73 */74goog.math.Coordinate.equals = function(a, b) {75  if (a == b) {76    return true;77  }78  if (!a || !b) {79    return false;80  }81  return a.x == b.x && a.y == b.y;82};838485/**86 * Returns the distance between two coordinates.87 * @param {!goog.math.Coordinate} a A Coordinate.88 * @param {!goog.math.Coordinate} b A Coordinate.89 * @return {number} The distance between {@code a} and {@code b}.90 */91goog.math.Coordinate.distance = function(a, b) {92  var dx = a.x - b.x;93  var dy = a.y - b.y;94  return Math.sqrt(dx * dx + dy * dy);95};969798/**99 * Returns the magnitude of a coordinate.100 * @param {!goog.math.Coordinate} a A Coordinate.101 * @return {number} The distance between the origin and {@code a}.102 */103goog.math.Coordinate.magnitude = function(a) {104  return Math.sqrt(a.x * a.x + a.y * a.y);105};106107108/**109 * Returns the angle from the origin to a coordinate.110 * @param {!goog.math.Coordinate} a A Coordinate.111 * @return {number} The angle, in degrees, clockwise from the positive X112 *     axis to {@code a}.113 */114goog.math.Coordinate.azimuth = function(a) {115  return goog.math.angle(0, 0, a.x, a.y);116};117118119/**120 * Returns the squared distance between two coordinates. Squared distances can121 * be used for comparisons when the actual value is not required.122 *123 * Performance note: eliminating the square root is an optimization often used124 * in lower-level languages, but the speed difference is not nearly as125 * pronounced in JavaScript (only a few percent.)126 *127 * @param {!goog.math.Coordinate} a A Coordinate.128 * @param {!goog.math.Coordinate} b A Coordinate.129 * @return {number} The squared distance between {@code a} and {@code b}.130 */131goog.math.Coordinate.squaredDistance = function(a, b) {132  var dx = a.x - b.x;133  var dy = a.y - b.y;134  return dx * dx + dy * dy;135};136137138/**139 * Returns the difference between two coordinates as a new140 * goog.math.Coordinate.141 * @param {!goog.math.Coordinate} a A Coordinate.142 * @param {!goog.math.Coordinate} b A Coordinate.143 * @return {!goog.math.Coordinate} A Coordinate representing the difference144 *     between {@code a} and {@code b}.145 */146goog.math.Coordinate.difference = function(a, b) {147  return new goog.math.Coordinate(a.x - b.x, a.y - b.y);148};149150151/**152 * Returns the sum of two coordinates as a new goog.math.Coordinate.153 * @param {!goog.math.Coordinate} a A Coordinate.154 * @param {!goog.math.Coordinate} b A Coordinate.155 * @return {!goog.math.Coordinate} A Coordinate representing the sum of the two156 *     coordinates.157 */158goog.math.Coordinate.sum = function(a, b) {159  return new goog.math.Coordinate(a.x + b.x, a.y + b.y);160};161162163/**164 * Rounds the x and y fields to the next larger integer values.165 * @return {!goog.math.Coordinate} This coordinate with ceil'd fields.166 */167goog.math.Coordinate.prototype.ceil = function() {168  this.x = Math.ceil(this.x);169  this.y = Math.ceil(this.y);170  return this;171};172173174/**175 * Rounds the x and y fields to the next smaller integer values.176 * @return {!goog.math.Coordinate} This coordinate with floored fields.177 */178goog.math.Coordinate.prototype.floor = function() {179  this.x = Math.floor(this.x);180  this.y = Math.floor(this.y);181  return this;182};183184185/**186 * Rounds the x and y fields to the nearest integer values.187 * @return {!goog.math.Coordinate} This coordinate with rounded fields.188 */189goog.math.Coordinate.prototype.round = function() {190  this.x = Math.round(this.x);191  this.y = Math.round(this.y);192  return this;193};194195196/**197 * Translates this box by the given offsets. If a {@code goog.math.Coordinate}198 * is given, then the x and y values are translated by the coordinate's x and y.199 * Otherwise, x and y are translated by {@code tx} and {@code opt_ty}200 * respectively.201 * @param {number|goog.math.Coordinate} tx The value to translate x by or the202 *     the coordinate to translate this coordinate by.203 * @param {number=} opt_ty The value to translate y by.204 * @return {!goog.math.Coordinate} This coordinate after translating.205 */206goog.math.Coordinate.prototype.translate = function(tx, opt_ty) {207  if (tx instanceof goog.math.Coordinate) {208    this.x += tx.x;209    this.y += tx.y;210  } else {211    this.x += tx;212    if (goog.isNumber(opt_ty)) {213      this.y += opt_ty;214    }215  }216  return this;217};218219220/**221 * Scales this coordinate by the given scale factors. The x and y values are222 * scaled by {@code sx} and {@code opt_sy} respectively.  If {@code opt_sy}223 * is not given, then {@code sx} is used for both x and y.224 * @param {number} sx The scale factor to use for the x dimension.225 * @param {number=} opt_sy The scale factor to use for the y dimension.226 * @return {!goog.math.Coordinate} This coordinate after scaling.227 */228goog.math.Coordinate.prototype.scale = function(sx, opt_sy) {229  var sy = goog.isNumber(opt_sy) ? opt_sy : sx;230  this.x *= sx;231  this.y *= sy;232  return this;233};234235236/**237 * Rotates this coordinate clockwise about the origin (or, optionally, the given238 * center) by the given angle, in radians.239 * @param {number} radians The angle by which to rotate this coordinate240 *     clockwise about the given center, in radians.241 * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults242 *     to (0, 0) if not given.243 */244goog.math.Coordinate.prototype.rotateRadians = function(radians, opt_center) {245  var center = opt_center || new goog.math.Coordinate(0, 0);246247  var x = this.x;248  var y = this.y;249  var cos = Math.cos(radians);250  var sin = Math.sin(radians);251252  this.x = (x - center.x) * cos - (y - center.y) * sin + center.x;253  this.y = (x - center.x) * sin + (y - center.y) * cos + center.y;254};255256257/**258 * Rotates this coordinate clockwise about the origin (or, optionally, the given259 * center) by the given angle, in degrees.260 * @param {number} degrees The angle by which to rotate this coordinate261 *     clockwise about the given center, in degrees.262 * @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults263 *     to (0, 0) if not given.264 */265goog.math.Coordinate.prototype.rotateDegrees = function(degrees, opt_center) {266  this.rotateRadians(goog.math.toRadians(degrees), opt_center);267};