CCPointExtension.js 13 KB

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