1 /**
  2  * The Render Engine
  3  * Point2D
  4  *
  5  * @fileoverview A Point2D class
  6  *
  7  * @author: Brett Fattori (brettf@renderengine.com)
  8  * @author: $Author: bfattori $
  9  * @version: $Revision: 1555 $
 10  *
 11  * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com)
 12  *
 13  * Permission is hereby granted, free of charge, to any person obtaining a copy
 14  * of this software and associated documentation files (the "Software"), to deal
 15  * in the Software without restriction, including without limitation the rights
 16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 17  * copies of the Software, and to permit persons to whom the Software is
 18  * furnished to do so, subject to the following conditions:
 19  *
 20  * The above copyright notice and this permission notice shall be included in
 21  * all copies or substantial portions of the Software.
 22  *
 23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 29  * THE SOFTWARE.
 30  *
 31  */
 32 
 33 // The class this file defines and its required classes
 34 R.Engine.define({
 35     "class":"R.math.Point2D",
 36     "requires":[
 37         "R.math.PooledMathObject",
 38         "R.math.Math2D"
 39     ]
 40 });
 41 
 42 /**
 43  * @class A 2D point class with helpful methods for manipulation
 44  *
 45  * @param x {R.math.Point2D|Number} If this arg is a R.math.Point2D, its values will be
 46  *                           copied into the new point.
 47  * @param y {Number} The Y coordinate of the point.  Only required if X
 48  *                   was a number.
 49  * @constructor
 50  * @description Create a new 2D point.
 51  * @extends R.math.PooledMathObject
 52  */
 53 R.math.Point2D = function () {
 54     "use strict";
 55     return R.math.PooledMathObject.extend(/** @scope R.math.Point2D.prototype */{
 56 
 57         x:0,
 58         y:0,
 59         __POINT2D:true,
 60 
 61         /**
 62          * @private
 63          */
 64         constructor:function (x, y) {
 65             this.base("Point2D");
 66             this.__POINT2D = true;
 67             return this.set(x, y);
 68         },
 69 
 70         /**
 71          * Release this point into the pool for reuse.
 72          */
 73         release:function () {
 74             this.base();
 75             this.x = 0;
 76             this.y = 0;
 77         },
 78 
 79         /**
 80          * Returns a simplified version of a R.math.Point2D.  The simplified version is
 81          * an array with two elements: X, Y.
 82          * @return {Array}
 83          */
 84         simplify:function () {
 85             return [this.x, this.y];
 86         },
 87 
 88         /**
 89          * Returns <tt>true</tt> if this point is equal to the specified point.
 90          *
 91          * @param point {R.math.Point2D} The point to compare to
 92          * @return {Boolean} <tt>true</tt> if the two points are equal
 93          */
 94         equals:function (point) {
 95             return (this.x == point.x && this.y == point.y);
 96         },
 97 
 98         /**
 99          * Set the position of a 2D point.
100          *
101          * @param x {R.math.Point2D|Number|Array} If this arg is a R.math.Point2D, its values will be
102          *                           copied into the new point.
103          * @param y {Number} The Y coordinate of the point.  Only required if X
104          *                   was a number.
105          */
106         set:function (x, y) {
107             if (R.isArray(x)) {
108                 // An array
109                 this.x = x[0];
110                 this.y = x[1];
111             }
112             else if (x.__POINT2D) {   // Instead of an "instanceof" check
113                 this.x = x.x;
114                 this.y = x.y;
115             }
116             else {
117                 AssertWarn((y != null), "Undefined Y value for point initialized to zero.");
118                 this.x = x;
119                 this.y = y || 0;
120             }
121             return this;
122         },
123 
124         /**
125          * Set the X coordinate.
126          *
127          * @param x {Number} The X coordinate
128          */
129         setX:function (x) {
130             this.x = x;
131         },
132 
133         /**
134          * Set the Y coordinate.
135          *
136          * @param y {Number} The Y coordinate
137          */
138         setY:function (y) {
139             this.y = y;
140         },
141 
142         /**
143          * A method that mutates this point by adding the point to it.
144          *
145          * @param point {R.math.Point2D} A point
146          * @return {R.math.Point2D} This point
147          */
148         add:function (point) {
149             Assert(point != null, "Adding undefined point");
150             this.x += point.x;
151             this.y += point.y;
152             return this;
153         },
154 
155         /**
156          * A mutator method that adds the scalar value to each component of this point.
157          * @param scalar {Number} A number
158          * @return {R.math.Point2D} This point
159          */
160         addScalar:function (scalar) {
161             Assert(scalar != null, "Adding undefined scalar");
162             this.x += scalar;
163             this.y += scalar;
164             return this;
165         },
166 
167         /**
168          * A mutator method that subtracts the specified point from this point.
169          * @param point {Point2D} a point
170          * @return {R.math.Point2D} This point
171          */
172         sub:function (point) {
173             Assert(point != null, "Subtracting undefined point");
174             this.x -= point.x;
175             this.y -= point.y;
176             return this;
177         },
178 
179         /**
180          * A mutator method that multiplies the components of this point with another.
181          * @param point {R.math.Point2D} A point
182          * @return {R.math.Point2D} This point
183          */
184         convolve:function (point) {
185             Assert(point != null, "Convolving undefined point");
186             this.x *= point.x;
187             this.y *= point.y;
188             return this;
189         },
190 
191         /**
192          * A mutator method that divides the components of this point by another.  The point
193          * cannot contain zeros for its components.
194          * @param point {R.math.Point2D} A point
195          * @return {R.math.Point2D} This point
196          */
197         convolveInverse:function (point) {
198             Assert(point != null, "Inverse convolving undefined point");
199             Assert((point.x != 0 && point.y != 0), "Division by zero in Point2D.convolveInverse");
200             this.x /= point.x;
201             this.y /= point.y;
202             return this;
203         },
204 
205         /**
206          * A mutator methor that multiplies the components of this point by a scalar value.
207          * @param scalar {Number} A number
208          * @return {R.math.Point2D} This point
209          */
210         mul:function (scalar) {
211             Assert(scalar != null, "Multiplying undefined scalar");
212             this.x *= scalar;
213             this.y *= scalar;
214             return this;
215         },
216 
217         /**
218          * A mutator method that divides the components of this point by a scalar value.
219          * @param scalar {Number} A number - cannot be zero
220          * @return {R.math.Point2D} This point
221          */
222         div:function (scalar) {
223             Assert(scalar != null, "Dividing undefined scalar");
224             Assert((scalar != 0), "Division by zero in Point2D.divScalar");
225             this.x /= scalar;
226             this.y /= scalar;
227             return this;
228         },
229 
230         /**
231          * A mutator method that negates this point, inversing it's components.
232          * @return {R.math.Point2D} This point
233          */
234         neg:function () {
235             this.x *= -1;
236             this.y *= -1;
237             return this;
238         },
239 
240         /**
241          * Returns true if the point is the zero point.
242          * @return {Boolean} <tt>true</tt> if the point's elements are both zero.
243          */
244         isZero:function () {
245             return this.x == 0 && this.y == 0;
246         },
247 
248         /**
249          * Returns the distance between this and another point.
250          * @param point {R.math.Point2D} The point to compare against
251          * @return {Number} The distance between the two points
252          */
253         dist:function (point) {
254             Assert(point != null, "Cannot solve distance to undefined point");
255             return Math.sqrt((point.x - this.x) * (point.x - this.x) +
256                 (point.y - this.y) * (point.y - this.y));
257         },
258 
259         /**
260          * Mutator method which transforms this point by the specified matrix
261          * @param matrix {Matrix} The matrix to transform this point by.  <tt>Matrix</tt>
262          * is defined in the Sylvester library.
263          *
264          * @return {R.math.Point2D} This point
265          */
266         transform:function (matrix) {
267             var v = matrix.multiply({ modulus:true, elements:[this.x, this.y, 1] });
268             this.x = v.elements[0];
269             this.y = v.elements[1];
270             return this;
271         },
272 
273         jitter:function (amt) {
274             var j = R.math.Point2D.create(R.lang.Math2.randomRange(-amt, amt, true),
275                 R.lang.Math2.randomRange(-amt, amt, true));
276 
277             this.add(j);
278             j.destroy();
279             return this;
280         },
281 
282         /**
283          * Returns a printable version of this object fixed to two decimal places.
284          * @return {String} Formatted as "x,y"
285          */
286         toString:function () {
287             return Number(this.x).toFixed(2) + "," + Number(this.y).toFixed(2);
288         }
289 
290     }, /** @scope R.math.Point2D.prototype */{
291         /**
292          * Return the classname of the this object
293          * @return {String} "R.math.Point2D"
294          */
295         getClassName:function () {
296             return "R.math.Point2D";
297         },
298 
299         /** @private */
300         resolved:function () {
301             R.math.Point2D.ZERO = R.math.Point2D.create(0, 0);
302             if (Object.freeze) {
303                 Object.freeze(R.math.Point2D.ZERO);
304             }
305         },
306 
307         /**
308          * The "zero" point. This point should not be modified.
309          * @type {Point2D}
310          */
311         ZERO:null
312     });
313 };