1 /**
  2  * The Render Engine
  3  * Circle2D
  4  *
  5  * @fileoverview A Circle2D 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.Circle2D",
 36     "requires":[
 37         "R.math.PooledMathObject",
 38         "R.math.Point2D",
 39         "R.math.Rectangle2D",
 40         "R.math.Math2D"
 41     ]
 42 });
 43 
 44 /**
 45  * @class A 2D circle class with helpful manipulation methods.
 46  * @extends R.math.PooledMathObject
 47  * @constructor
 48  * @param x {Number} The center X coordinate
 49  * @param y {Number} The center Y coordinate
 50  * @param radius {Number} The radius of the circle
 51  * @description Create a circle object specifying the X and Y center position and
 52  *     the radius.
 53  */
 54 R.math.Circle2D = function () {
 55     "use strict";
 56     return R.math.PooledMathObject.extend(/** @scope R.math.Circle2D.prototype */{
 57 
 58         center:null,
 59         radius:0,
 60         __CIRCLE2D:true,
 61 
 62         /** @private */
 63         constructor:function (x, y, radius) {
 64             this.__CIRCLE2D = true;
 65             this.center = R.math.Point2D.create(0, 0);
 66             this.radius = 0;
 67             this.set(x, y, radius);
 68         },
 69 
 70         /**
 71          * Destroy the instance of the circle
 72          */
 73         destroy:function () {
 74             if (this.center) {
 75                 this.center.destroy();
 76             }
 77             this.base();
 78         },
 79 
 80         /**
 81          * Release the circle back into the pool for reuse.
 82          */
 83         release:function () {
 84             this.base();
 85             this.center = null;
 86             this.radius = 0;
 87         },
 88 
 89         /**
 90          * Set the values of this circle.
 91          *
 92          * @param x {Number|R.math.Point2D|R.math.Circle2D} An optional value to initialize the X coordinate of the circle
 93          * @param y {Number} An optional value to initialize the Y coordinate of the circle
 94          * @param radius {Number} An optional value to initialize the radius
 95          */
 96         set:function (x, y, radius) {
 97             if (x.__CIRCLE2D) {
 98                 this.center.set(x.getCenter());
 99                 this.radius = x.getRadius();
100             }
101             else if (x.__POINT2D) {
102                 this.center.set(x);
103                 this.radius = y;
104             }
105             else {
106                 this.center.set(x || 0, y || 0);
107                 this.radius = radius || 0.0;
108             }
109         },
110 
111         /**
112          * Get an object with the elements containing centerX, centerY, and radius
113          * as the elements x, y, and r.
114          *
115          * @return {Object} An object with the specified elements
116          */
117         get:function () {
118             var c = this.getCenter();
119             return {
120                 x:c.x,
121                 y:c.y,
122                 r:this.getRadius()
123             };
124         },
125 
126         /**
127          * Returns <tt>true</tt> if this circle is equal to the specified circle.
128          *
129          * @param circle {R.math.Circle2D} The circle to compare to
130          * @return {Boolean} <tt>true</tt> if the two circles are equal
131          */
132         equals:function (circle) {
133             return (this.center.equals(circle.getCenter()) && this.radius == circle.getRadius());
134         },
135 
136         /**
137          * Offset this circle by the given amount in the X and Y axis.  The first parameter
138          * can be either a {@link Point2D}, or the value for the X axis.  If the X axis is specified,
139          * the second parameter should be the amount to offset in the Y axis.
140          *
141          * @param offsetPtOrX {R.math.Point2D|int} Either a {@link R.math.Point2D} which contains the offset in X and Y, or an integer
142          *                                representing the offset in the X axis.
143          * @param offsetY {int} If <code>offsetPtOrX</code> is an integer value for the offset in the X axis, this should be
144          *                      the offset along the Y axis.
145          */
146         offset:function (offsetPtOrX, offsetY) {
147             var offs = R.math.Point2D.create(0, 0);
148             if (offsetPtOrX.__POINT2D) {
149                 offs.set(offsetPtOrX);
150             }
151             else {
152                 offs.set(offsetPtOrX, offsetY);
153             }
154 
155             this.center.add(offs);
156             offs.destroy();
157             return this;
158         },
159 
160         /**
161          * Get the center point of this circle.
162          * @return {R.math.Point2D} The center point
163          */
164         getCenter:function () {
165             return this.center;
166         },
167 
168         /**
169          * Get the radius of this circle
170          * @return {Number} The radius
171          */
172         getRadius:function () {
173             return this.radius;
174         },
175 
176         /**
177          * Determine if this circle intersects another circle.
178          *
179          * @param circle A {@link R.math.Circle2D} to compare against
180          * @return {Boolean} <tt>true</tt> if the two circles intersect.
181          */
182         isIntersecting:function (circle) {
183             var c1 = this.getCenter();
184             var c2 = circle.getCenter();
185             var dX = (c1.x - c2.x) * (c1.x - c2.x);
186             var dY = (c1.y - c2.y) * (c1.y - c2.y);
187             var r2 = (this.getRadius() + circle.getRadius()) * (this.getRadius() + circle.getRadius());
188             return (dX + dY <= r2);
189         },
190 
191         /**
192          * Determine if this circle is contained within the specified circle.
193          *
194          * @param circle {R.math.Circle2D} A circle to compare against
195          * @return {Boolean} <tt>true</tt> if the this circle is fully contained in the specified circle.
196          */
197         isContained:function (circle) {
198             var d = circle.getCenter().dist(this.getCenter());
199             return (d < (this.getRadius() + circle.getRadius()));
200         },
201 
202         /**
203          * Determine if this circle contains the specified circle.
204          *
205          * @param circle {R.math.Circle2D} A circle to compare against
206          * @return {Boolean} <tt>true</tt> if the rectangle is fully contained within this rectangle.
207          */
208         containsCircle:function (circle) {
209             return circle.isContained(this);
210         },
211 
212         /**
213          * Returns <tt>true</tt> if this circle contains the specified point.
214          *
215          * @param point {R.math.Point2D} The point to test
216          * @return {Boolean} <tt>true</tt> if the point is within the circle
217          */
218         containsPoint:function (point) {
219             var c1 = this.getCenter();
220             var r = this.getRadius();
221             return (c1.dist(point) <= r);
222         },
223 
224         /**
225          * Returns a printable version of this object.
226          * @return {String} Formatted like "cX,cY r#"
227          */
228         toString:function () {
229             return this.center.toString() + " r" + Number(this.radius).toFixed(2);
230         }
231 
232     }, /** @scope R.math.Circle2D.prototype */{
233         /**
234          * Return the classname of the this object
235          * @return {String} "R.math.Circle2D"
236          */
237         getClassName:function () {
238             return "R.math.Circle2D";
239         },
240 
241         /**
242          * Approximate a circle from the given rectangle
243          * @param rect {R.math.Rectangle2D} The rectangle to use
244          * @return {R.math.Circle2D}
245          */
246         approximateFromRectangle:function (rect) {
247             // Determine the center & radius
248             var r = Math.max(rect.getHalfWidth(), rect.getHalfHeight()),
249                 c = rect.getCenter();
250             return R.math.Circle2D.create(c.x, c.y, r);
251         }
252 
253     });
254 
255 };