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