1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * <p>cc.Point extensions based on Chipmunk's cpVect file.<br />
 29  * These extensions work both with cc.Point</p>
 30  *
 31  * <p>The "ccp" prefix means: "CoCos2d Point"</p>
 32  *
 33  * <p> //Examples:<br />
 34  * - cc.pAdd( cc.p(1,1), cc.p(2,2) ); // preferred cocos2d way<br />
 35  * - cc.pAdd( cc.p(1,1), cc.p(2,2) ); // also ok but more verbose<br />
 36  * - cc.pAdd( cc.cpv(1,1), cc.cpv(2,2) ); // mixing chipmunk and cocos2d (avoid)</p>
 37  */
 38 
 39 /**
 40  * smallest such that 1.0+FLT_EPSILON != 1.0
 41  * @constant
 42  * @type Number
 43  */
 44 cc.POINT_EPSILON = parseFloat('1.192092896e-07F');
 45 
 46 /**
 47  * Returns opposite of point.
 48  * @param {cc.Point} point
 49  * @return {cc.Point}
 50  */
 51 cc.pNeg = function (point) {
 52     return cc.p(-point.x, -point.y);
 53 };
 54 
 55 /**
 56  * Calculates sum of two points.
 57  * @param {cc.Point} v1
 58  * @param {cc.Point} v2
 59  * @return {cc.Point}
 60  */
 61 cc.pAdd = function (v1, v2) {
 62     return cc.p(v1.x + v2.x, v1.y + v2.y);
 63 };
 64 
 65 /**
 66  * Calculates difference of two points.
 67  * @param {cc.Point} v1
 68  * @param {cc.Point} v2
 69  * @return {cc.Point}
 70  */
 71 cc.pSub = function (v1, v2) {
 72     return cc.p(v1.x - v2.x, v1.y - v2.y);
 73 };
 74 
 75 /**
 76  * Returns point multiplied by given factor.
 77  * @param {cc.Point} point
 78  * @param {Number} floatVar
 79  * @return {cc.Point}
 80  */
 81 cc.pMult = function (point, floatVar) {
 82     return cc.p(point.x * floatVar, point.y * floatVar);
 83 };
 84 
 85 /**
 86  * Calculates midpoint between two points.
 87  * @param {cc.Point} v1
 88  * @param {cc.Point} v2
 89  * @return {cc.pMult}
 90  */
 91 cc.pMidpoint = function (v1, v2) {
 92     return cc.pMult(cc.pAdd(v1, v2), 0.5);
 93 };
 94 
 95 /**
 96  * Calculates dot product of two points.
 97  * @param {cc.Point} v1
 98  * @param {cc.Point} v2
 99  * @return {Number}
100  */
101 cc.pDot = function (v1, v2) {
102     return v1.x * v2.x + v1.y * v2.y;
103 };
104 
105 /**
106  * Calculates cross product of two points.
107  * @param {cc.Point} v1
108  * @param {cc.Point} v2
109  * @return {Number}
110  */
111 cc.pCross = function (v1, v2) {
112     return v1.x * v2.y - v1.y * v2.x;
113 };
114 
115 /**
116  * Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0
117  * @param {cc.Point} point
118  * @return {cc.Point}
119  */
120 cc.pPerp = function (point) {
121     return cc.p(-point.y, point.x);
122 };
123 
124 /**
125  * Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0
126  * @param {cc.Point} point
127  * @return {cc.Point}
128  */
129 cc.pRPerp = function (point) {
130     return cc.p(point.y, -point.x);
131 };
132 
133 /**
134  * Calculates the projection of v1 over v2.
135  * @param {cc.Point} v1
136  * @param {cc.Point} v2
137  * @return {cc.pMult}
138  */
139 cc.pProject = function (v1, v2) {
140     return cc.pMult(v2, cc.pDot(v1, v2) / cc.pDot(v2, v2));
141 };
142 
143 /**
144  * Rotates two points.
145  * @param  {cc.Point} v1
146  * @param  {cc.Point} v2
147  * @return {cc.Point}
148  */
149 cc.pRotate = function (v1, v2) {
150     return cc.p(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x);
151 };
152 
153 /**
154  * Unrotates two points.
155  * @param  {cc.Point} v1
156  * @param  {cc.Point} v2
157  * @return {cc.Point}
158  */
159 cc.pUnrotate = function (v1, v2) {
160     return cc.p(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y);
161 };
162 
163 /**
164  * Calculates the square length of a cc.Point (not calling sqrt() )
165  * @param  {cc.Point} v
166  *@return {cc.pDot}
167  */
168 cc.pLengthSQ = function (v) {
169     return cc.pDot(v, v);
170 };
171 
172 /**
173  * Calculates distance between point an origin
174  * @param  {cc.Point} v
175  * @return {Number}
176  */
177 cc.pLength = function (v) {
178     return Math.sqrt(cc.pLengthSQ(v));
179 };
180 
181 /**
182  * Calculates the distance between two points
183  * @param {cc.Point} v1
184  * @param {cc.Point} v2
185  * @return {cc.pLength}
186  */
187 cc.pDistance = function (v1, v2) {
188     return cc.pLength(cc.pSub(v1, v2));
189 };
190 
191 /**
192  * Returns point multiplied to a length of 1.
193  * @param {cc.Point} v
194  * @return {cc.pMult}
195  */
196 cc.pNormalize = function (v) {
197     return cc.pMult(v, 1.0 / cc.pLength(v));
198 };
199 
200 /**
201  * Converts radians to a normalized vector.
202  * @param {Number} a
203  * @return {cc.Point}
204  */
205 cc.pForAngle = function (a) {
206     return cc.p(Math.cos(a), Math.sin(a));
207 };
208 
209 /**
210  * Converts a vector to radians.
211  * @param {cc.Point} v
212  * @return {Number}
213  */
214 cc.pToAngle = function (v) {
215     return Math.atan2(v.y, v.x);
216 };
217 
218 /**
219  * Clamp a value between from and to.
220  * @param {Number} value
221  * @param {Number} min_inclusive
222  * @param {Number} max_inclusive
223  * @return {Number}
224  */
225 cc.clampf = function (value, min_inclusive, max_inclusive) {
226     if (min_inclusive > max_inclusive) {
227         var temp = min_inclusive;
228         min_inclusive = max_inclusive;
229         max_inclusive = temp;
230     }
231     return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive;
232 };
233 
234 /**
235  * Clamp a point between from and to.
236  * @param {Number} p
237  * @param {Number} min_inclusive
238  * @param {Number} max_inclusive
239  * @return {cc.Point}
240  */
241 cc.pClamp = function (p, min_inclusive, max_inclusive) {
242     return cc.p(cc.clampf(p.x, min_inclusive.x, max_inclusive.x), cc.clampf(p.y, min_inclusive.y, max_inclusive.y));
243 };
244 
245 /**
246  * Quickly convert cc.Size to a cc.Point
247  * @param {cc.Size} s
248  * @return {cc.Point}
249  */
250 cc.pFromSize = function (s) {
251     return cc.p(s.width, s.height);
252 };
253 
254 /**
255  * Run a math operation function on each point component <br />
256  * Math.abs, Math.fllor, Math.ceil, Math.round.
257  * @param {cc.Point} p
258  * @param {Function} opFunc
259  * @return {cc.Point}
260  * @example
261  * //For example: let's try to take the floor of x,y
262  * var p = cc.pCompOp(cc.p(10,10),Math.abs);
263  */
264 cc.pCompOp = function (p, opFunc) {
265     return cc.p(opFunc(p.x), opFunc(p.y));
266 };
267 
268 /**
269  * Linear Interpolation between two points a and b
270  * alpha == 0 ? a
271  * alpha == 1 ? b
272  * otherwise a value between a..b
273  * @param {cc.Point} a
274  * @param {cc.Point} b
275  * @param {Number} alpha
276  * @return {cc.pAdd}
277  */
278 cc.pLerp = function (a, b, alpha) {
279     return cc.pAdd(cc.pMult(a, 1 - alpha), cc.pMult(b, alpha));
280 };
281 
282 /**
283  * @param {cc.Point} a
284  * @param {cc.Point} b
285  * @param {Number} variance
286  * @return {Boolean} if points have fuzzy equality which means equal with some degree of variance.
287  */
288 cc.pFuzzyEqual = function (a, b, variance) {
289     if (a.x - variance <= b.x && b.x <= a.x + variance) {
290         if (a.y - variance <= b.y && b.y <= a.y + variance) {
291             return true;
292         }
293     }
294     return false;
295 };
296 
297 /**
298  * Multiplies a nd b components, a.x*b.x, a.y*b.y
299  * @param {cc.Point} a
300  * @param {cc.Point} b
301  * @return {cc.Point}
302  */
303 cc.pCompMult = function (a, b) {
304     return cc.p(a.x * b.x, a.y * b.y);
305 };
306 
307 /**
308  * @param {cc.Point} a
309  * @param {cc.Point} b
310  * @return {Number} the signed angle in radians between two vector directions
311  */
312 cc.pAngleSigned = function (a, b) {
313     var a2 = cc.pNormalize(a);
314     var b2 = cc.pNormalize(b);
315     var angle = Math.atan2(a2.x * b2.y - a2.y * b2.x, cc.pDot(a2, b2));
316     if (Math.abs(angle) < cc.POINT_EPSILON) {
317         return 0.0;
318     }
319     return angle;
320 };
321 
322 /**
323  * @param {cc.Point} a
324  * @param {cc.Point} b
325  * @return {Number} the angle in radians between two vector directions
326  */
327 cc.pAngle = function (a, b) {
328     var angle = Math.acos(cc.pDot(cc.pNormalize(a), cc.pNormalize(b)));
329     if (Math.abs(angle) < cc.POINT_EPSILON) return 0.0;
330     return angle;
331 };
332 
333 /**
334  * Rotates a point counter clockwise by the angle around a pivot
335  * @param {cc.Point} v v is the point to rotate
336  * @param {cc.Point} pivot pivot is the pivot, naturally
337  * @param {Number} angle angle is the angle of rotation cw in radians
338  * @return {cc.Point} the rotated point
339  */
340 cc.pRotateByAngle = function (v, pivot, angle) {
341     var r = cc.pSub(v, pivot);
342     var cosa = Math.cos(angle), sina = Math.sin(angle);
343     var t = r.x;
344     r.x = t * cosa - r.y * sina + pivot.x;
345     r.y = t * sina + r.y * cosa + pivot.y;
346     return r;
347 };
348 
349 /**
350  * A general line-line intersection test
351  * @param {cc.Point} A A is the startpoint for the first line P1 = (p1 - p2).
352  * @param {cc.Point} B B is the endpoint for the first line P1 = (p1 - p2).
353  * @param {cc.Point} C C is the startpoint for the second line P2 = (p3 - p4).
354  * @param {cc.Point} D D is the endpoint for the second line P2 = (p3 - p4).
355  * @param {cc.Point} retP retP.x is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)), <br />
356  * retP.y is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)).
357  * @return {Boolean}
358  * indicating successful intersection of a line<br />
359  * note that to truly test intersection for segments we have to make<br />
360  * sure that s & t lie within [0..1] and for rays, make sure s & t > 0<br />
361  * the hit point is        p3 + t * (p4 - p3);<br />
362  * the hit point also is    p1 + s * (p2 - p1);
363  */
364 cc.pLineIntersect = function (A, B, C, D, retP) {
365     if ((A.x == B.x && A.y == B.y) || (C.x == D.x && C.y == D.y)) {
366         return false;
367     }
368     var BAx = B.x - A.x;
369     var BAy = B.y - A.y;
370     var DCx = D.x - C.x;
371     var DCy = D.y - C.y;
372     var ACx = A.x - C.x;
373     var ACy = A.y - C.y;
374 
375     var denom = DCy * BAx - DCx * BAy;
376 
377     retP.x = DCx * ACy - DCy * ACx;
378     retP.y = BAx * ACy - BAy * ACx;
379 
380     if (denom == 0) {
381         if (retP.x == 0 || retP.y == 0) {
382             // Lines incident
383             return true;
384         }
385         // Lines parallel and not incident
386         return false;
387     }
388 
389     retP.x = retP.x / denom;
390     retP.y = retP.y / denom;
391 
392     return true;
393 };
394 
395 /**
396  * ccpSegmentIntersect return YES if Segment A-B intersects with segment C-D.
397  * @param {cc.Point} A
398  * @param {cc.Point} B
399  * @param {cc.Point} C
400  * @param {cc.Point} D
401  * @return {Boolean}
402  */
403 cc.pSegmentIntersect = function (A, B, C, D) {
404     var retP = cc.p(0, 0);
405     if (cc.pLineIntersect(A, B, C, D, retP))
406         if (retP.x >= 0.0 && retP.x <= 1.0 && retP.y >= 0.0 && retP.y <= 1.0)
407             return true;
408     return false;
409 };
410 
411 /**
412  * ccpIntersectPoint return the intersection point of line A-B, C-D
413  * @param {cc.Point} A
414  * @param {cc.Point} B
415  * @param {cc.Point} C
416  * @param {cc.Point} D
417  * @return {cc.Point}
418  */
419 cc.pIntersectPoint = function (A, B, C, D) {
420     var retP = cc.p(0, 0);
421 
422     if (cc.pLineIntersect(A, B, C, D, retP)) {
423         // Point of intersection
424         var P = cc.p(0, 0);
425         P.x = A.x + retP.x * (B.x - A.x);
426         P.y = A.y + retP.x * (B.y - A.y);
427         return P;
428     }
429 
430     return cc.PointZero();
431 };
432 
433 /**
434  * check to see if both points are equal
435  * @param {cc.Point} A A ccp a
436  * @param {cc.Point} B B ccp b to be compared
437  * @return {Boolean} the true if both ccp are same
438  */
439 cc.pSameAs = function (A, B) {
440     if (A.x && B.x) {
441         return (A.x == B.x && A.y == B.y);
442     }
443     return false;
444 };
445