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