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 {Number}
167  */
168 cc.pLengthSQ = function (v) {
169     return cc.pDot(v, v);
170 };
171 
172 /**
173  * Calculates the square distance between two points (not calling sqrt() )
174  * @param {cc.Point} point1
175  * @param {cc.Point} point2
176  * @return {Number}
177  */
178 cc.pDistanceSQ = function(point1, point2){
179     return cc.pLengthSQ(cc.pSub(point1,point2));
180 };
181 
182 /**
183  * Calculates distance between point an origin
184  * @param  {cc.Point} v
185  * @return {Number}
186  */
187 cc.pLength = function (v) {
188     return Math.sqrt(cc.pLengthSQ(v));
189 };
190 
191 /**
192  * Calculates the distance between two points
193  * @param {cc.Point} v1
194  * @param {cc.Point} v2
195  * @return {cc.pLength}
196  */
197 cc.pDistance = function (v1, v2) {
198     return cc.pLength(cc.pSub(v1, v2));
199 };
200 
201 /**
202  * Returns point multiplied to a length of 1.
203  * @param {cc.Point} v
204  * @return {cc.Point}
205  */
206 cc.pNormalize = function (v) {
207     return cc.pMult(v, 1.0 / cc.pLength(v));
208 };
209 
210 /**
211  * Converts radians to a normalized vector.
212  * @param {Number} a
213  * @return {cc.Point}
214  */
215 cc.pForAngle = function (a) {
216     return cc.p(Math.cos(a), Math.sin(a));
217 };
218 
219 /**
220  * Converts a vector to radians.
221  * @param {cc.Point} v
222  * @return {Number}
223  */
224 cc.pToAngle = function (v) {
225     return Math.atan2(v.y, v.x);
226 };
227 
228 /**
229  * Clamp a value between from and to.
230  * @param {Number} value
231  * @param {Number} min_inclusive
232  * @param {Number} max_inclusive
233  * @return {Number}
234  */
235 cc.clampf = function (value, min_inclusive, max_inclusive) {
236     if (min_inclusive > max_inclusive) {
237         var temp = min_inclusive;
238         min_inclusive = max_inclusive;
239         max_inclusive = temp;
240     }
241     return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive;
242 };
243 
244 /**
245  * Clamp a point between from and to.
246  * @param {Point} p
247  * @param {Number} min_inclusive
248  * @param {Number} max_inclusive
249  * @return {cc.Point}
250  */
251 cc.pClamp = function (p, min_inclusive, max_inclusive) {
252     return cc.p(cc.clampf(p.x, min_inclusive.x, max_inclusive.x), cc.clampf(p.y, min_inclusive.y, max_inclusive.y));
253 };
254 
255 /**
256  * Quickly convert cc.Size to a cc.Point
257  * @param {cc.Size} s
258  * @return {cc.Point}
259  */
260 cc.pFromSize = function (s) {
261     return cc.p(s.width, s.height);
262 };
263 
264 /**
265  * Run a math operation function on each point component <br />
266  * Math.abs, Math.fllor, Math.ceil, Math.round.
267  * @param {cc.Point} p
268  * @param {Function} opFunc
269  * @return {cc.Point}
270  * @example
271  * //For example: let's try to take the floor of x,y
272  * var p = cc.pCompOp(cc.p(10,10),Math.abs);
273  */
274 cc.pCompOp = function (p, opFunc) {
275     return cc.p(opFunc(p.x), opFunc(p.y));
276 };
277 
278 /**
279  * Linear Interpolation between two points a and b
280  * alpha == 0 ? a
281  * alpha == 1 ? b
282  * otherwise a value between a..b
283  * @param {cc.Point} a
284  * @param {cc.Point} b
285  * @param {Number} alpha
286  * @return {cc.pAdd}
287  */
288 cc.pLerp = function (a, b, alpha) {
289     return cc.pAdd(cc.pMult(a, 1 - alpha), cc.pMult(b, alpha));
290 };
291 
292 /**
293  * @param {cc.Point} a
294  * @param {cc.Point} b
295  * @param {Number} variance
296  * @return {Boolean} if points have fuzzy equality which means equal with some degree of variance.
297  */
298 cc.pFuzzyEqual = function (a, b, variance) {
299     if (a.x - variance <= b.x && b.x <= a.x + variance) {
300         if (a.y - variance <= b.y && b.y <= a.y + variance)
301             return true;
302     }
303     return false;
304 };
305 
306 /**
307  * Multiplies a nd b components, a.x*b.x, a.y*b.y
308  * @param {cc.Point} a
309  * @param {cc.Point} b
310  * @return {cc.Point}
311  */
312 cc.pCompMult = function (a, b) {
313     return cc.p(a.x * b.x, a.y * b.y);
314 };
315 
316 /**
317  * @param {cc.Point} a
318  * @param {cc.Point} b
319  * @return {Number} the signed angle in radians between two vector directions
320  */
321 cc.pAngleSigned = function (a, b) {
322     var a2 = cc.pNormalize(a);
323     var b2 = cc.pNormalize(b);
324     var angle = Math.atan2(a2.x * b2.y - a2.y * b2.x, cc.pDot(a2, b2));
325     if (Math.abs(angle) < cc.POINT_EPSILON)
326         return 0.0;
327     return angle;
328 };
329 
330 /**
331  * @param {cc.Point} a
332  * @param {cc.Point} b
333  * @return {Number} the angle in radians between two vector directions
334  */
335 cc.pAngle = function (a, b) {
336     var angle = Math.acos(cc.pDot(cc.pNormalize(a), cc.pNormalize(b)));
337     if (Math.abs(angle) < cc.POINT_EPSILON) return 0.0;
338     return angle;
339 };
340 
341 /**
342  * Rotates a point counter clockwise by the angle around a pivot
343  * @param {cc.Point} v v is the point to rotate
344  * @param {cc.Point} pivot pivot is the pivot, naturally
345  * @param {Number} angle angle is the angle of rotation cw in radians
346  * @return {cc.Point} the rotated point
347  */
348 cc.pRotateByAngle = function (v, pivot, angle) {
349     var r = cc.pSub(v, pivot);
350     var cosa = Math.cos(angle), sina = Math.sin(angle);
351     var t = r.x;
352     r.x = t * cosa - r.y * sina + pivot.x;
353     r.y = t * sina + r.y * cosa + pivot.y;
354     return r;
355 };
356 
357 /**
358  * A general line-line intersection test
359  * @param {cc.Point} A A is the startpoint for the first line P1 = (p1 - p2).
360  * @param {cc.Point} B B is the endpoint for the first line P1 = (p1 - p2).
361  * @param {cc.Point} C C is the startpoint for the second line P2 = (p3 - p4).
362  * @param {cc.Point} D D is the endpoint for the second line P2 = (p3 - p4).
363  * @param {cc.Point} retP retP.x is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)), <br />
364  * retP.y is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)).
365  * @return {Boolean}
366  * indicating successful intersection of a line<br />
367  * note that to truly test intersection for segments we have to make<br />
368  * sure that s & t lie within [0..1] and for rays, make sure s & t > 0<br />
369  * the hit point is        p3 + t * (p4 - p3);<br />
370  * the hit point also is    p1 + s * (p2 - p1);
371  */
372 cc.pLineIntersect = function (A, B, C, D, retP) {
373     if ((A.x == B.x && A.y == B.y) || (C.x == D.x && C.y == D.y)) {
374         return false;
375     }
376     var BAx = B.x - A.x;
377     var BAy = B.y - A.y;
378     var DCx = D.x - C.x;
379     var DCy = D.y - C.y;
380     var ACx = A.x - C.x;
381     var ACy = A.y - C.y;
382 
383     var denom = DCy * BAx - DCx * BAy;
384 
385     retP.x = DCx * ACy - DCy * ACx;
386     retP.y = BAx * ACy - BAy * ACx;
387 
388     if (denom == 0) {
389         if (retP.x == 0 || retP.y == 0) {
390             // Lines incident
391             return true;
392         }
393         // Lines parallel and not incident
394         return false;
395     }
396 
397     retP.x = retP.x / denom;
398     retP.y = retP.y / denom;
399 
400     return true;
401 };
402 
403 /**
404  * ccpSegmentIntersect return YES if Segment A-B intersects with segment C-D.
405  * @param {cc.Point} A
406  * @param {cc.Point} B
407  * @param {cc.Point} C
408  * @param {cc.Point} D
409  * @return {Boolean}
410  */
411 cc.pSegmentIntersect = function (A, B, C, D) {
412     var retP = cc.p(0, 0);
413     if (cc.pLineIntersect(A, B, C, D, retP))
414         if (retP.x >= 0.0 && retP.x <= 1.0 && retP.y >= 0.0 && retP.y <= 1.0)
415             return true;
416     return false;
417 };
418 
419 /**
420  * ccpIntersectPoint return the intersection point of line A-B, C-D
421  * @param {cc.Point} A
422  * @param {cc.Point} B
423  * @param {cc.Point} C
424  * @param {cc.Point} D
425  * @return {cc.Point}
426  */
427 cc.pIntersectPoint = function (A, B, C, D) {
428     var retP = cc.p(0, 0);
429 
430     if (cc.pLineIntersect(A, B, C, D, retP)) {
431         // Point of intersection
432         var P = cc.p(0, 0);
433         P.x = A.x + retP.x * (B.x - A.x);
434         P.y = A.y + retP.x * (B.y - A.y);
435         return P;
436     }
437 
438     return cc.PointZero();
439 };
440 
441 /**
442  * check to see if both points are equal
443  * @param {cc.Point} A A ccp a
444  * @param {cc.Point} B B ccp b to be compared
445  * @return {Boolean} the true if both ccp are same
446  */
447 cc.pSameAs = function (A, B) {
448     if ((A != null) && (B != null)) {
449         return (A.x == B.x && A.y == B.y);
450     }
451     return false;
452 };
453 
454 
455 
456 // High Perfomance In Place Operationrs ---------------------------------------
457 
458 /**
459   * sets the position of the point to 0
460   */
461 cc.pZeroIn = function(v) {
462     v.x = 0;
463     v.y = 0;
464 };
465 
466 /**
467   * copies the position of one point to another
468   */
469 cc.pIn = function(v1, v2) {
470     v1.x = v2.x;
471     v1.y = v2.y;
472 };
473 
474 /**
475   * multiplies the point with the given factor (inplace)
476   */
477 cc.pMultIn = function(point, floatVar) {
478     point.x *= floatVar;
479     point.y *= floatVar;
480 };
481 
482 /**
483   * subtracts one point from another (inplace)
484   */
485 cc.pSubIn = function(v1, v2) {
486     v1.x -= v2.x;
487     v1.y -= v2.y;
488 };
489 
490 /**
491   * adds one point to another (inplace)
492   */
493 cc.pAddIn = function(v1, v2) {
494     v1.x += v2.x;
495     v1.y += v2.y;
496 };
497 
498 /**
499   * normalizes the point (inplace)
500   */
501 cc.pNormalizeIn = function(v) {
502     cc.pMultIn(v, 1.0 / Math.sqrt(v.x * v.x + v.y * v.y));
503 };
504 
505