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