BoundingBoxData.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /**
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2012-2017 DragonBones team and other contributors
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  7. * this software and associated documentation files (the "Software"), to deal in
  8. * the Software without restriction, including without limitation the rights to
  9. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10. * the Software, and to permit persons to whom the Software is furnished to do so,
  11. * subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. using System;
  24. using System.Collections.Generic;
  25. namespace DragonBones
  26. {
  27. /// <summary>
  28. /// - The base class of bounding box data.
  29. /// </summary>
  30. /// <see cref="DragonBones.RectangleData"/>
  31. /// <see cref="DragonBones.EllipseData"/>
  32. /// <see cref="DragonBones.PolygonData"/>
  33. /// <version>DragonBones 5.0</version>
  34. /// <language>en_US</language>
  35. /// <summary>
  36. /// - 边界框数据基类。
  37. /// </summary>
  38. /// <see cref="DragonBones.RectangleData"/>
  39. /// <see cref="DragonBones.EllipseData"/>
  40. /// <see cref="DragonBones.PolygonData"/>
  41. /// <version>DragonBones 5.0</version>
  42. /// <language>zh_CN</language>
  43. public abstract class BoundingBoxData : BaseObject
  44. {
  45. /// <summary>
  46. /// - The bounding box type.
  47. /// </summary>
  48. /// <version>DragonBones 5.0</version>
  49. /// <language>en_US</language>
  50. /// <summary>
  51. /// - 边界框类型。
  52. /// </summary>
  53. /// <version>DragonBones 5.0</version>
  54. /// <language>zh_CN</language>
  55. public BoundingBoxType type;
  56. /// <private/>
  57. public uint color;
  58. /// <private/>
  59. public float width;
  60. /// <private/>
  61. public float height;
  62. /// <private/>
  63. protected override void _OnClear()
  64. {
  65. this.color = 0x000000;
  66. this.width = 0.0f;
  67. this.height = 0.0f;
  68. }
  69. /// <summary>
  70. /// - Check whether the bounding box contains a specific point. (Local coordinate system)
  71. /// </summary>
  72. /// <version>DragonBones 5.0</version>
  73. /// <language>en_US</language>
  74. /// <summary>
  75. /// - 检查边界框是否包含特定点。(本地坐标系)
  76. /// </summary>
  77. /// <version>DragonBones 5.0</version>
  78. /// <language>zh_CN</language>
  79. public abstract bool ContainsPoint(float pX, float pY);
  80. /// <summary>
  81. /// - Check whether the bounding box intersects a specific segment. (Local coordinate system)
  82. /// </summary>
  83. /// <version>DragonBones 5.0</version>
  84. /// <language>en_US</language>
  85. /// <summary>
  86. /// - 检查边界框是否与特定线段相交。(本地坐标系)
  87. /// </summary>
  88. /// <version>DragonBones 5.0</version>
  89. /// <language>zh_CN</language>
  90. public abstract int IntersectsSegment(float xA, float yA, float xB, float yB,
  91. Point intersectionPointA = null,
  92. Point intersectionPointB = null,
  93. Point normalRadians = null);
  94. }
  95. /// <summary>
  96. /// - Cohen–Sutherland algorithm https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
  97. /// ----------------------
  98. /// | 0101 | 0100 | 0110 |
  99. /// ----------------------
  100. /// | 0001 | 0000 | 0010 |
  101. /// ----------------------
  102. /// | 1001 | 1000 | 1010 |
  103. /// ----------------------
  104. /// </summary>
  105. enum OutCode
  106. {
  107. InSide = 0, // 0000
  108. Left = 1, // 0001
  109. Right = 2, // 0010
  110. Top = 4, // 0100
  111. Bottom = 8 // 1000
  112. }
  113. /// <summary>
  114. /// - The rectangle bounding box data.
  115. /// </summary>
  116. /// <version>DragonBones 5.1</version>
  117. /// <language>en_US</language>
  118. /// <summary>
  119. /// - 矩形边界框数据。
  120. /// </summary>
  121. /// <version>DragonBones 5.1</version>
  122. /// <language>zh_CN</language>
  123. public class RectangleBoundingBoxData : BoundingBoxData
  124. {
  125. /// <summary>
  126. /// - Compute the bit code for a point (x, y) using the clip rectangle
  127. /// </summary>
  128. private static int _ComputeOutCode(float x, float y, float xMin, float yMin, float xMax, float yMax)
  129. {
  130. var code = OutCode.InSide; // initialised as being inside of [[clip window]]
  131. if (x < xMin)
  132. { // to the left of clip window
  133. code |= OutCode.Left;
  134. }
  135. else if (x > xMax)
  136. { // to the right of clip window
  137. code |= OutCode.Right;
  138. }
  139. if (y < yMin)
  140. { // below the clip window
  141. code |= OutCode.Top;
  142. }
  143. else if (y > yMax)
  144. { // above the clip window
  145. code |= OutCode.Bottom;
  146. }
  147. return (int)code;
  148. }
  149. /// <private/>
  150. public static int RectangleIntersectsSegment(float xA, float yA, float xB, float yB,
  151. float xMin, float yMin, float xMax, float yMax,
  152. Point intersectionPointA = null,
  153. Point intersectionPointB = null,
  154. Point normalRadians = null)
  155. {
  156. var inSideA = xA > xMin && xA < xMax && yA > yMin && yA < yMax;
  157. var inSideB = xB > xMin && xB < xMax && yB > yMin && yB < yMax;
  158. if (inSideA && inSideB)
  159. {
  160. return -1;
  161. }
  162. var intersectionCount = 0;
  163. var outcode0 = RectangleBoundingBoxData._ComputeOutCode(xA, yA, xMin, yMin, xMax, yMax);
  164. var outcode1 = RectangleBoundingBoxData._ComputeOutCode(xB, yB, xMin, yMin, xMax, yMax);
  165. while (true)
  166. {
  167. if ((outcode0 | outcode1) == 0)
  168. { // Bitwise OR is 0. Trivially accept and get out of loop
  169. intersectionCount = 2;
  170. break;
  171. }
  172. else if ((outcode0 & outcode1) != 0)
  173. { // Bitwise AND is not 0. Trivially reject and get out of loop
  174. break;
  175. }
  176. // failed both tests, so calculate the line segment to clip
  177. // from an outside point to an intersection with clip edge
  178. var x = 0.0f;
  179. var y = 0.0f;
  180. var normalRadian = 0.0f;
  181. // At least one endpoint is outside the clip rectangle; pick it.
  182. var outcodeOut = outcode0 != 0 ? outcode0 : outcode1;
  183. // Now find the intersection point;
  184. if ((outcodeOut & (int)OutCode.Top) != 0)
  185. { // point is above the clip rectangle
  186. x = xA + (xB - xA) * (yMin - yA) / (yB - yA);
  187. y = yMin;
  188. if (normalRadians != null)
  189. {
  190. normalRadian = -(float)Math.PI * 0.5f;
  191. }
  192. }
  193. else if ((outcodeOut & (int)OutCode.Bottom) != 0)
  194. { // point is below the clip rectangle
  195. x = xA + (xB - xA) * (yMax - yA) / (yB - yA);
  196. y = yMax;
  197. if (normalRadians != null)
  198. {
  199. normalRadian = (float)Math.PI * 0.5f;
  200. }
  201. }
  202. else if ((outcodeOut & (int)OutCode.Right) != 0)
  203. { // point is to the right of clip rectangle
  204. y = yA + (yB - yA) * (xMax - xA) / (xB - xA);
  205. x = xMax;
  206. if (normalRadians != null)
  207. {
  208. normalRadian = 0;
  209. }
  210. }
  211. else if ((outcodeOut & (int)OutCode.Left) != 0)
  212. { // point is to the left of clip rectangle
  213. y = yA + (yB - yA) * (xMin - xA) / (xB - xA);
  214. x = xMin;
  215. if (normalRadians != null)
  216. {
  217. normalRadian = (float)Math.PI;
  218. }
  219. }
  220. // Now we move outside point to intersection point to clip
  221. // and get ready for next pass.
  222. if (outcodeOut == outcode0)
  223. {
  224. xA = x;
  225. yA = y;
  226. outcode0 = RectangleBoundingBoxData._ComputeOutCode(xA, yA, xMin, yMin, xMax, yMax);
  227. if (normalRadians != null)
  228. {
  229. normalRadians.x = normalRadian;
  230. }
  231. }
  232. else
  233. {
  234. xB = x;
  235. yB = y;
  236. outcode1 = RectangleBoundingBoxData._ComputeOutCode(xB, yB, xMin, yMin, xMax, yMax);
  237. if (normalRadians != null)
  238. {
  239. normalRadians.y = normalRadian;
  240. }
  241. }
  242. }
  243. if (intersectionCount > 0)
  244. {
  245. if (inSideA)
  246. {
  247. intersectionCount = 2; // 10
  248. if (intersectionPointA != null)
  249. {
  250. intersectionPointA.x = xB;
  251. intersectionPointA.y = yB;
  252. }
  253. if (intersectionPointB != null)
  254. {
  255. intersectionPointB.x = xB;
  256. intersectionPointB.y = xB;
  257. }
  258. if (normalRadians != null)
  259. {
  260. normalRadians.x = normalRadians.y + (float)Math.PI;
  261. }
  262. }
  263. else if (inSideB)
  264. {
  265. intersectionCount = 1; // 01
  266. if (intersectionPointA != null)
  267. {
  268. intersectionPointA.x = xA;
  269. intersectionPointA.y = yA;
  270. }
  271. if (intersectionPointB != null)
  272. {
  273. intersectionPointB.x = xA;
  274. intersectionPointB.y = yA;
  275. }
  276. if (normalRadians != null)
  277. {
  278. normalRadians.y = normalRadians.x + (float)Math.PI;
  279. }
  280. }
  281. else
  282. {
  283. intersectionCount = 3; // 11
  284. if (intersectionPointA != null)
  285. {
  286. intersectionPointA.x = xA;
  287. intersectionPointA.y = yA;
  288. }
  289. if (intersectionPointB != null)
  290. {
  291. intersectionPointB.x = xB;
  292. intersectionPointB.y = yB;
  293. }
  294. }
  295. }
  296. return intersectionCount;
  297. }
  298. /// <inheritDoc/>
  299. /// <private/>
  300. protected override void _OnClear()
  301. {
  302. base._OnClear();
  303. this.type = BoundingBoxType.Rectangle;
  304. }
  305. /// <inheritDoc/>
  306. public override bool ContainsPoint(float pX, float pY)
  307. {
  308. var widthH = this.width * 0.5f;
  309. if (pX >= -widthH && pX <= widthH)
  310. {
  311. var heightH = this.height * 0.5f;
  312. if (pY >= -heightH && pY <= heightH)
  313. {
  314. return true;
  315. }
  316. }
  317. return false;
  318. }
  319. /// <inheritDoc/>
  320. public override int IntersectsSegment(float xA, float yA, float xB, float yB,
  321. Point intersectionPointA = null,
  322. Point intersectionPointB = null,
  323. Point normalRadians = null)
  324. {
  325. var widthH = this.width * 0.5f;
  326. var heightH = this.height * 0.5f;
  327. var intersectionCount = RectangleBoundingBoxData.RectangleIntersectsSegment
  328. (
  329. xA, yA, xB, yB,
  330. -widthH, -heightH, widthH, heightH,
  331. intersectionPointA, intersectionPointB, normalRadians
  332. );
  333. return intersectionCount;
  334. }
  335. }
  336. /// <summary>
  337. /// - The ellipse bounding box data.
  338. /// </summary>
  339. /// <version>DragonBones 5.1</version>
  340. /// <language>en_US</language>
  341. /// <summary>
  342. /// - 椭圆边界框数据。
  343. /// </summary>
  344. /// <version>DragonBones 5.1</version>
  345. /// <language>zh_CN</language>
  346. public class EllipseBoundingBoxData : BoundingBoxData
  347. {
  348. /// <private/>
  349. public static int EllipseIntersectsSegment(float xA, float yA, float xB, float yB,
  350. float xC, float yC, float widthH, float heightH,
  351. Point intersectionPointA = null,
  352. Point intersectionPointB = null,
  353. Point normalRadians = null)
  354. {
  355. var d = widthH / heightH;
  356. var dd = d * d;
  357. yA *= d;
  358. yB *= d;
  359. var dX = xB - xA;
  360. var dY = yB - yA;
  361. var lAB = (float)Math.Sqrt(dX * dX + dY * dY);
  362. var xD = dX / lAB;
  363. var yD = dY / lAB;
  364. var a = (xC - xA) * xD + (yC - yA) * yD;
  365. var aa = a * a;
  366. var ee = xA * xA + yA * yA;
  367. var rr = widthH * widthH;
  368. var dR = rr - ee + aa;
  369. var intersectionCount = 0;
  370. if (dR >= 0.0f)
  371. {
  372. var dT = (float)Math.Sqrt(dR);
  373. var sA = a - dT;
  374. var sB = a + dT;
  375. var inSideA = sA < 0.0 ? -1 : (sA <= lAB ? 0 : 1);
  376. var inSideB = sB < 0.0 ? -1 : (sB <= lAB ? 0 : 1);
  377. var sideAB = inSideA * inSideB;
  378. if (sideAB < 0)
  379. {
  380. return -1;
  381. }
  382. else if (sideAB == 0)
  383. {
  384. if (inSideA == -1)
  385. {
  386. intersectionCount = 2; // 10
  387. xB = xA + sB * xD;
  388. yB = (yA + sB * yD) / d;
  389. if (intersectionPointA != null)
  390. {
  391. intersectionPointA.x = xB;
  392. intersectionPointA.y = yB;
  393. }
  394. if (intersectionPointB != null)
  395. {
  396. intersectionPointB.x = xB;
  397. intersectionPointB.y = yB;
  398. }
  399. if (normalRadians != null)
  400. {
  401. normalRadians.x = (float)Math.Atan2(yB / rr * dd, xB / rr);
  402. normalRadians.y = normalRadians.x + (float)Math.PI;
  403. }
  404. }
  405. else if (inSideB == 1)
  406. {
  407. intersectionCount = 1; // 01
  408. xA = xA + sA * xD;
  409. yA = (yA + sA * yD) / d;
  410. if (intersectionPointA != null)
  411. {
  412. intersectionPointA.x = xA;
  413. intersectionPointA.y = yA;
  414. }
  415. if (intersectionPointB != null)
  416. {
  417. intersectionPointB.x = xA;
  418. intersectionPointB.y = yA;
  419. }
  420. if (normalRadians != null)
  421. {
  422. normalRadians.x = (float)Math.Atan2(yA / rr * dd, xA / rr);
  423. normalRadians.y = normalRadians.x + (float)Math.PI;
  424. }
  425. }
  426. else
  427. {
  428. intersectionCount = 3; // 11
  429. if (intersectionPointA != null)
  430. {
  431. intersectionPointA.x = xA + sA * xD;
  432. intersectionPointA.y = (yA + sA * yD) / d;
  433. if (normalRadians != null)
  434. {
  435. normalRadians.x = (float)Math.Atan2(intersectionPointA.y / rr * dd, intersectionPointA.x / rr);
  436. }
  437. }
  438. if (intersectionPointB != null)
  439. {
  440. intersectionPointB.x = xA + sB * xD;
  441. intersectionPointB.y = (yA + sB * yD) / d;
  442. if (normalRadians != null)
  443. {
  444. normalRadians.y = (float)Math.Atan2(intersectionPointB.y / rr * dd, intersectionPointB.x / rr);
  445. }
  446. }
  447. }
  448. }
  449. }
  450. return intersectionCount;
  451. }
  452. /// <inheritDoc/>
  453. /// <private/>
  454. protected override void _OnClear()
  455. {
  456. base._OnClear();
  457. this.type = BoundingBoxType.Ellipse;
  458. }
  459. /// <inheritDoc/>
  460. public override bool ContainsPoint(float pX, float pY)
  461. {
  462. var widthH = this.width * 0.5f;
  463. if (pX >= -widthH && pX <= widthH)
  464. {
  465. var heightH = this.height * 0.5f;
  466. if (pY >= -heightH && pY <= heightH)
  467. {
  468. pY *= widthH / heightH;
  469. return Math.Sqrt(pX * pX + pY * pY) <= widthH;
  470. }
  471. }
  472. return false;
  473. }
  474. /// <inheritDoc/>
  475. public override int IntersectsSegment(float xA, float yA, float xB, float yB,
  476. Point intersectionPointA,
  477. Point intersectionPointB,
  478. Point normalRadians)
  479. {
  480. var intersectionCount = EllipseBoundingBoxData.EllipseIntersectsSegment(xA, yA, xB, yB,
  481. 0.0f, 0.0f, this.width * 0.5f, this.height * 0.5f,
  482. intersectionPointA, intersectionPointB, normalRadians);
  483. return intersectionCount;
  484. }
  485. }
  486. /// <summary>
  487. /// - The polygon bounding box data.
  488. /// </summary>
  489. /// <version>DragonBones 5.1</version>
  490. /// <language>en_US</language>
  491. /// <summary>
  492. /// - 多边形边界框数据。
  493. /// </summary>
  494. /// <version>DragonBones 5.1</version>
  495. /// <language>zh_CN</language>
  496. public class PolygonBoundingBoxData : BoundingBoxData
  497. {
  498. /// <private/>
  499. public static int PolygonIntersectsSegment(float xA, float yA, float xB, float yB,
  500. List<float> vertices,
  501. Point intersectionPointA = null,
  502. Point intersectionPointB = null,
  503. Point normalRadians = null)
  504. {
  505. if (xA == xB)
  506. {
  507. xA = xB + 0.01f;
  508. }
  509. if (yA == yB)
  510. {
  511. yA = yB + 0.01f;
  512. }
  513. var l = vertices.Count;
  514. var dXAB = xA - xB;
  515. var dYAB = yA - yB;
  516. var llAB = xA * yB - yA * xB;
  517. int intersectionCount = 0;
  518. var xC = vertices[l - 2];
  519. var yC = vertices[l - 1];
  520. var dMin = 0.0f;
  521. var dMax = 0.0f;
  522. var xMin = 0.0f;
  523. var yMin = 0.0f;
  524. var xMax = 0.0f;
  525. var yMax = 0.0f;
  526. for (int i = 0; i < l; i += 2)
  527. {
  528. var xD = vertices[i];
  529. var yD = vertices[i + 1];
  530. if (xC == xD)
  531. {
  532. xC = xD + 0.01f;
  533. }
  534. if (yC == yD)
  535. {
  536. yC = yD + 0.01f;
  537. }
  538. var dXCD = xC - xD;
  539. var dYCD = yC - yD;
  540. var llCD = xC * yD - yC * xD;
  541. var ll = dXAB * dYCD - dYAB * dXCD;
  542. var x = (llAB * dXCD - dXAB * llCD) / ll;
  543. if (((x >= xC && x <= xD) || (x >= xD && x <= xC)) && (dXAB == 0 || (x >= xA && x <= xB) || (x >= xB && x <= xA)))
  544. {
  545. var y = (llAB * dYCD - dYAB * llCD) / ll;
  546. if (((y >= yC && y <= yD) || (y >= yD && y <= yC)) && (dYAB == 0 || (y >= yA && y <= yB) || (y >= yB && y <= yA)))
  547. {
  548. if (intersectionPointB != null)
  549. {
  550. var d = x - xA;
  551. if (d < 0.0f)
  552. {
  553. d = -d;
  554. }
  555. if (intersectionCount == 0)
  556. {
  557. dMin = d;
  558. dMax = d;
  559. xMin = x;
  560. yMin = y;
  561. xMax = x;
  562. yMax = y;
  563. if (normalRadians != null)
  564. {
  565. normalRadians.x = (float)Math.Atan2(yD - yC, xD - xC) - (float)Math.PI * 0.5f;
  566. normalRadians.y = normalRadians.x;
  567. }
  568. }
  569. else
  570. {
  571. if (d < dMin)
  572. {
  573. dMin = d;
  574. xMin = x;
  575. yMin = y;
  576. if (normalRadians != null)
  577. {
  578. normalRadians.x = (float)Math.Atan2(yD - yC, xD - xC) - (float)Math.PI * 0.5f;
  579. }
  580. }
  581. if (d > dMax)
  582. {
  583. dMax = d;
  584. xMax = x;
  585. yMax = y;
  586. if (normalRadians != null)
  587. {
  588. normalRadians.y = (float)Math.Atan2(yD - yC, xD - xC) - (float)Math.PI * 0.5f;
  589. }
  590. }
  591. }
  592. intersectionCount++;
  593. }
  594. else
  595. {
  596. xMin = x;
  597. yMin = y;
  598. xMax = x;
  599. yMax = y;
  600. intersectionCount++;
  601. if (normalRadians != null)
  602. {
  603. normalRadians.x = (float)Math.Atan2(yD - yC, xD - xC) - (float)Math.PI * 0.5f;
  604. normalRadians.y = normalRadians.x;
  605. }
  606. break;
  607. }
  608. }
  609. }
  610. xC = xD;
  611. yC = yD;
  612. }
  613. if (intersectionCount == 1)
  614. {
  615. if (intersectionPointA != null)
  616. {
  617. intersectionPointA.x = xMin;
  618. intersectionPointA.y = yMin;
  619. }
  620. if (intersectionPointB != null)
  621. {
  622. intersectionPointB.x = xMin;
  623. intersectionPointB.y = yMin;
  624. }
  625. if (normalRadians != null)
  626. {
  627. normalRadians.y = normalRadians.x + (float)Math.PI;
  628. }
  629. }
  630. else if (intersectionCount > 1)
  631. {
  632. intersectionCount++;
  633. if (intersectionPointA != null)
  634. {
  635. intersectionPointA.x = xMin;
  636. intersectionPointA.y = yMin;
  637. }
  638. if (intersectionPointB != null)
  639. {
  640. intersectionPointB.x = xMax;
  641. intersectionPointB.y = yMax;
  642. }
  643. }
  644. return intersectionCount;
  645. }
  646. /// <private/>
  647. public float x;
  648. /// <private/>
  649. public float y;
  650. /// <summary>
  651. /// - The polygon vertices.
  652. /// </summary>
  653. /// <version>DragonBones 5.1</version>
  654. /// <language>en_US</language>
  655. /// <summary>
  656. /// - 多边形顶点。
  657. /// </summary>
  658. /// <version>DragonBones 5.1</version>
  659. /// <language>zh_CN</language>
  660. public readonly List<float> vertices = new List<float>();
  661. /// <inheritDoc/>
  662. /// <private/>
  663. protected override void _OnClear()
  664. {
  665. base._OnClear();
  666. this.type = BoundingBoxType.Polygon;
  667. this.x = 0.0f;
  668. this.y = 0.0f;
  669. this.vertices.Clear();
  670. }
  671. /// <inheritDoc/>
  672. public override bool ContainsPoint(float pX, float pY)
  673. {
  674. var isInSide = false;
  675. if (pX >= this.x && pX <= this.width && pY >= this.y && pY <= this.height)
  676. {
  677. for (int i = 0, l = this.vertices.Count, iP = l - 2; i < l; i += 2)
  678. {
  679. var yA = this.vertices[iP + 1];
  680. var yB = this.vertices[i + 1];
  681. if ((yB < pY && yA >= pY) || (yA < pY && yB >= pY))
  682. {
  683. var xA = this.vertices[iP];
  684. var xB = this.vertices[i];
  685. if ((pY - yB) * (xA - xB) / (yA - yB) + xB < pX)
  686. {
  687. isInSide = !isInSide;
  688. }
  689. }
  690. iP = i;
  691. }
  692. }
  693. return isInSide;
  694. }
  695. /// <inheritDoc/>
  696. public override int IntersectsSegment(float xA, float yA, float xB, float yB,
  697. Point intersectionPointA = null,
  698. Point intersectionPointB = null,
  699. Point normalRadians = null)
  700. {
  701. var intersectionCount = 0;
  702. if (RectangleBoundingBoxData.RectangleIntersectsSegment(xA, yA, xB, yB, this.x, this.y, this.x + this.width, this.y + this.height, null, null, null) != 0)
  703. {
  704. intersectionCount = PolygonBoundingBoxData.PolygonIntersectsSegment
  705. (
  706. xA, yA, xB, yB,
  707. this.vertices,
  708. intersectionPointA, intersectionPointB, normalRadians
  709. );
  710. }
  711. return intersectionCount;
  712. }
  713. }
  714. }