AABB.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. #if REAL_T_IS_DOUBLE
  2. using real_t = System.Double;
  3. #else
  4. using real_t = System.Single;
  5. #endif
  6. using System;
  7. using System.Runtime.InteropServices;
  8. namespace Godot
  9. {
  10. /// <summary>
  11. /// Axis-Aligned Bounding Box. AABB consists of a position, a size, and
  12. /// several utility functions. It is typically used for fast overlap tests.
  13. /// </summary>
  14. [Serializable]
  15. [StructLayout(LayoutKind.Sequential)]
  16. public struct AABB : IEquatable<AABB>
  17. {
  18. private Vector3 _position;
  19. private Vector3 _size;
  20. /// <summary>
  21. /// Beginning corner. Typically has values lower than End.
  22. /// </summary>
  23. /// <value>Directly uses a private field.</value>
  24. public Vector3 Position
  25. {
  26. get { return _position; }
  27. set { _position = value; }
  28. }
  29. /// <summary>
  30. /// Size from Position to End. Typically all components are positive.
  31. /// If the size is negative, you can use <see cref="Abs"/> to fix it.
  32. /// </summary>
  33. /// <value>Directly uses a private field.</value>
  34. public Vector3 Size
  35. {
  36. get { return _size; }
  37. set { _size = value; }
  38. }
  39. /// <summary>
  40. /// Ending corner. This is calculated as <see cref="Position"/> plus
  41. /// <see cref="Size"/>. Setting this value will change the size.
  42. /// </summary>
  43. /// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value>
  44. public Vector3 End
  45. {
  46. get { return _position + _size; }
  47. set { _size = value - _position; }
  48. }
  49. /// <summary>
  50. /// Returns an AABB with equivalent position and size, modified so that
  51. /// the most-negative corner is the origin and the size is positive.
  52. /// </summary>
  53. /// <returns>The modified AABB.</returns>
  54. public AABB Abs()
  55. {
  56. Vector3 end = End;
  57. Vector3 topLeft = new Vector3(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y), Mathf.Min(_position.z, end.z));
  58. return new AABB(topLeft, _size.Abs());
  59. }
  60. /// <summary>
  61. /// Returns true if this AABB completely encloses another one.
  62. /// </summary>
  63. /// <param name="with">The other AABB that may be enclosed.</param>
  64. /// <returns>A bool for whether or not this AABB encloses `b`.</returns>
  65. public bool Encloses(AABB with)
  66. {
  67. Vector3 srcMin = _position;
  68. Vector3 srcMax = _position + _size;
  69. Vector3 dstMin = with._position;
  70. Vector3 dstMax = with._position + with._size;
  71. return srcMin.x <= dstMin.x &&
  72. srcMax.x > dstMax.x &&
  73. srcMin.y <= dstMin.y &&
  74. srcMax.y > dstMax.y &&
  75. srcMin.z <= dstMin.z &&
  76. srcMax.z > dstMax.z;
  77. }
  78. /// <summary>
  79. /// Returns this AABB expanded to include a given point.
  80. /// </summary>
  81. /// <param name="point">The point to include.</param>
  82. /// <returns>The expanded AABB.</returns>
  83. public AABB Expand(Vector3 point)
  84. {
  85. Vector3 begin = _position;
  86. Vector3 end = _position + _size;
  87. if (point.x < begin.x)
  88. {
  89. begin.x = point.x;
  90. }
  91. if (point.y < begin.y)
  92. {
  93. begin.y = point.y;
  94. }
  95. if (point.z < begin.z)
  96. {
  97. begin.z = point.z;
  98. }
  99. if (point.x > end.x)
  100. {
  101. end.x = point.x;
  102. }
  103. if (point.y > end.y)
  104. {
  105. end.y = point.y;
  106. }
  107. if (point.z > end.z)
  108. {
  109. end.z = point.z;
  110. }
  111. return new AABB(begin, end - begin);
  112. }
  113. /// <summary>
  114. /// Returns the area of the AABB.
  115. /// </summary>
  116. /// <returns>The area.</returns>
  117. public real_t GetArea()
  118. {
  119. return _size.x * _size.y * _size.z;
  120. }
  121. /// <summary>
  122. /// Gets the position of one of the 8 endpoints of the AABB.
  123. /// </summary>
  124. /// <param name="idx">Which endpoint to get.</param>
  125. /// <returns>An endpoint of the AABB.</returns>
  126. public Vector3 GetEndpoint(int idx)
  127. {
  128. switch (idx)
  129. {
  130. case 0:
  131. return new Vector3(_position.x, _position.y, _position.z);
  132. case 1:
  133. return new Vector3(_position.x, _position.y, _position.z + _size.z);
  134. case 2:
  135. return new Vector3(_position.x, _position.y + _size.y, _position.z);
  136. case 3:
  137. return new Vector3(_position.x, _position.y + _size.y, _position.z + _size.z);
  138. case 4:
  139. return new Vector3(_position.x + _size.x, _position.y, _position.z);
  140. case 5:
  141. return new Vector3(_position.x + _size.x, _position.y, _position.z + _size.z);
  142. case 6:
  143. return new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z);
  144. case 7:
  145. return new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z + _size.z);
  146. default:
  147. {
  148. throw new ArgumentOutOfRangeException(nameof(idx),
  149. $"Index is {idx}, but a value from 0 to 7 is expected.");
  150. }
  151. }
  152. }
  153. /// <summary>
  154. /// Returns the normalized longest axis of the AABB.
  155. /// </summary>
  156. /// <returns>A vector representing the normalized longest axis of the AABB.</returns>
  157. public Vector3 GetLongestAxis()
  158. {
  159. var axis = new Vector3(1f, 0f, 0f);
  160. real_t maxSize = _size.x;
  161. if (_size.y > maxSize)
  162. {
  163. axis = new Vector3(0f, 1f, 0f);
  164. maxSize = _size.y;
  165. }
  166. if (_size.z > maxSize)
  167. {
  168. axis = new Vector3(0f, 0f, 1f);
  169. }
  170. return axis;
  171. }
  172. /// <summary>
  173. /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the AABB.
  174. /// </summary>
  175. /// <returns>A <see cref="Vector3.Axis"/> index for which axis is longest.</returns>
  176. public Vector3.Axis GetLongestAxisIndex()
  177. {
  178. var axis = Vector3.Axis.X;
  179. real_t maxSize = _size.x;
  180. if (_size.y > maxSize)
  181. {
  182. axis = Vector3.Axis.Y;
  183. maxSize = _size.y;
  184. }
  185. if (_size.z > maxSize)
  186. {
  187. axis = Vector3.Axis.Z;
  188. }
  189. return axis;
  190. }
  191. /// <summary>
  192. /// Returns the scalar length of the longest axis of the AABB.
  193. /// </summary>
  194. /// <returns>The scalar length of the longest axis of the AABB.</returns>
  195. public real_t GetLongestAxisSize()
  196. {
  197. real_t maxSize = _size.x;
  198. if (_size.y > maxSize)
  199. maxSize = _size.y;
  200. if (_size.z > maxSize)
  201. maxSize = _size.z;
  202. return maxSize;
  203. }
  204. /// <summary>
  205. /// Returns the normalized shortest axis of the AABB.
  206. /// </summary>
  207. /// <returns>A vector representing the normalized shortest axis of the AABB.</returns>
  208. public Vector3 GetShortestAxis()
  209. {
  210. var axis = new Vector3(1f, 0f, 0f);
  211. real_t maxSize = _size.x;
  212. if (_size.y < maxSize)
  213. {
  214. axis = new Vector3(0f, 1f, 0f);
  215. maxSize = _size.y;
  216. }
  217. if (_size.z < maxSize)
  218. {
  219. axis = new Vector3(0f, 0f, 1f);
  220. }
  221. return axis;
  222. }
  223. /// <summary>
  224. /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the AABB.
  225. /// </summary>
  226. /// <returns>A <see cref="Vector3.Axis"/> index for which axis is shortest.</returns>
  227. public Vector3.Axis GetShortestAxisIndex()
  228. {
  229. var axis = Vector3.Axis.X;
  230. real_t maxSize = _size.x;
  231. if (_size.y < maxSize)
  232. {
  233. axis = Vector3.Axis.Y;
  234. maxSize = _size.y;
  235. }
  236. if (_size.z < maxSize)
  237. {
  238. axis = Vector3.Axis.Z;
  239. }
  240. return axis;
  241. }
  242. /// <summary>
  243. /// Returns the scalar length of the shortest axis of the AABB.
  244. /// </summary>
  245. /// <returns>The scalar length of the shortest axis of the AABB.</returns>
  246. public real_t GetShortestAxisSize()
  247. {
  248. real_t maxSize = _size.x;
  249. if (_size.y < maxSize)
  250. maxSize = _size.y;
  251. if (_size.z < maxSize)
  252. maxSize = _size.z;
  253. return maxSize;
  254. }
  255. /// <summary>
  256. /// Returns the support point in a given direction.
  257. /// This is useful for collision detection algorithms.
  258. /// </summary>
  259. /// <param name="dir">The direction to find support for.</param>
  260. /// <returns>A vector representing the support.</returns>
  261. public Vector3 GetSupport(Vector3 dir)
  262. {
  263. Vector3 halfExtents = _size * 0.5f;
  264. Vector3 ofs = _position + halfExtents;
  265. return ofs + new Vector3(
  266. dir.x > 0f ? -halfExtents.x : halfExtents.x,
  267. dir.y > 0f ? -halfExtents.y : halfExtents.y,
  268. dir.z > 0f ? -halfExtents.z : halfExtents.z);
  269. }
  270. /// <summary>
  271. /// Returns a copy of the AABB grown a given amount of units towards all the sides.
  272. /// </summary>
  273. /// <param name="by">The amount to grow by.</param>
  274. /// <returns>The grown AABB.</returns>
  275. public AABB Grow(real_t by)
  276. {
  277. AABB res = this;
  278. res._position.x -= by;
  279. res._position.y -= by;
  280. res._position.z -= by;
  281. res._size.x += 2.0f * by;
  282. res._size.y += 2.0f * by;
  283. res._size.z += 2.0f * by;
  284. return res;
  285. }
  286. /// <summary>
  287. /// Returns true if the AABB is flat or empty, or false otherwise.
  288. /// </summary>
  289. /// <returns>A bool for whether or not the AABB has area.</returns>
  290. public bool HasNoArea()
  291. {
  292. return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f;
  293. }
  294. /// <summary>
  295. /// Returns true if the AABB has no surface (no size), or false otherwise.
  296. /// </summary>
  297. /// <returns>A bool for whether or not the AABB has area.</returns>
  298. public bool HasNoSurface()
  299. {
  300. return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f;
  301. }
  302. /// <summary>
  303. /// Returns true if the AABB contains a point, or false otherwise.
  304. /// </summary>
  305. /// <param name="point">The point to check.</param>
  306. /// <returns>A bool for whether or not the AABB contains `point`.</returns>
  307. public bool HasPoint(Vector3 point)
  308. {
  309. if (point.x < _position.x)
  310. return false;
  311. if (point.y < _position.y)
  312. return false;
  313. if (point.z < _position.z)
  314. return false;
  315. if (point.x > _position.x + _size.x)
  316. return false;
  317. if (point.y > _position.y + _size.y)
  318. return false;
  319. if (point.z > _position.z + _size.z)
  320. return false;
  321. return true;
  322. }
  323. /// <summary>
  324. /// Returns the intersection of this AABB and `b`.
  325. /// </summary>
  326. /// <param name="with">The other AABB.</param>
  327. /// <returns>The clipped AABB.</returns>
  328. public AABB Intersection(AABB with)
  329. {
  330. Vector3 srcMin = _position;
  331. Vector3 srcMax = _position + _size;
  332. Vector3 dstMin = with._position;
  333. Vector3 dstMax = with._position + with._size;
  334. Vector3 min, max;
  335. if (srcMin.x > dstMax.x || srcMax.x < dstMin.x)
  336. {
  337. return new AABB();
  338. }
  339. min.x = srcMin.x > dstMin.x ? srcMin.x : dstMin.x;
  340. max.x = srcMax.x < dstMax.x ? srcMax.x : dstMax.x;
  341. if (srcMin.y > dstMax.y || srcMax.y < dstMin.y)
  342. {
  343. return new AABB();
  344. }
  345. min.y = srcMin.y > dstMin.y ? srcMin.y : dstMin.y;
  346. max.y = srcMax.y < dstMax.y ? srcMax.y : dstMax.y;
  347. if (srcMin.z > dstMax.z || srcMax.z < dstMin.z)
  348. {
  349. return new AABB();
  350. }
  351. min.z = srcMin.z > dstMin.z ? srcMin.z : dstMin.z;
  352. max.z = srcMax.z < dstMax.z ? srcMax.z : dstMax.z;
  353. return new AABB(min, max - min);
  354. }
  355. /// <summary>
  356. /// Returns true if the AABB overlaps with `b`
  357. /// (i.e. they have at least one point in common).
  358. ///
  359. /// If `includeBorders` is true, they will also be considered overlapping
  360. /// if their borders touch, even without intersection.
  361. /// </summary>
  362. /// <param name="with">The other AABB to check for intersections with.</param>
  363. /// <param name="includeBorders">Whether or not to consider borders.</param>
  364. /// <returns>A bool for whether or not they are intersecting.</returns>
  365. public bool Intersects(AABB with, bool includeBorders = false)
  366. {
  367. if (includeBorders)
  368. {
  369. if (_position.x > with._position.x + with._size.x)
  370. return false;
  371. if (_position.x + _size.x < with._position.x)
  372. return false;
  373. if (_position.y > with._position.y + with._size.y)
  374. return false;
  375. if (_position.y + _size.y < with._position.y)
  376. return false;
  377. if (_position.z > with._position.z + with._size.z)
  378. return false;
  379. if (_position.z + _size.z < with._position.z)
  380. return false;
  381. }
  382. else
  383. {
  384. if (_position.x >= with._position.x + with._size.x)
  385. return false;
  386. if (_position.x + _size.x <= with._position.x)
  387. return false;
  388. if (_position.y >= with._position.y + with._size.y)
  389. return false;
  390. if (_position.y + _size.y <= with._position.y)
  391. return false;
  392. if (_position.z >= with._position.z + with._size.z)
  393. return false;
  394. if (_position.z + _size.z <= with._position.z)
  395. return false;
  396. }
  397. return true;
  398. }
  399. /// <summary>
  400. /// Returns true if the AABB is on both sides of `plane`.
  401. /// </summary>
  402. /// <param name="plane">The plane to check for intersection.</param>
  403. /// <returns>A bool for whether or not the AABB intersects the plane.</returns>
  404. public bool IntersectsPlane(Plane plane)
  405. {
  406. Vector3[] points =
  407. {
  408. new Vector3(_position.x, _position.y, _position.z),
  409. new Vector3(_position.x, _position.y, _position.z + _size.z),
  410. new Vector3(_position.x, _position.y + _size.y, _position.z),
  411. new Vector3(_position.x, _position.y + _size.y, _position.z + _size.z),
  412. new Vector3(_position.x + _size.x, _position.y, _position.z),
  413. new Vector3(_position.x + _size.x, _position.y, _position.z + _size.z),
  414. new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z),
  415. new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z + _size.z)
  416. };
  417. bool over = false;
  418. bool under = false;
  419. for (int i = 0; i < 8; i++)
  420. {
  421. if (plane.DistanceTo(points[i]) > 0)
  422. {
  423. over = true;
  424. }
  425. else
  426. {
  427. under = true;
  428. }
  429. }
  430. return under && over;
  431. }
  432. /// <summary>
  433. /// Returns true if the AABB intersects the line segment between `from` and `to`.
  434. /// </summary>
  435. /// <param name="from">The start of the line segment.</param>
  436. /// <param name="to">The end of the line segment.</param>
  437. /// <returns>A bool for whether or not the AABB intersects the line segment.</returns>
  438. public bool IntersectsSegment(Vector3 from, Vector3 to)
  439. {
  440. real_t min = 0f;
  441. real_t max = 1f;
  442. for (int i = 0; i < 3; i++)
  443. {
  444. real_t segFrom = from[i];
  445. real_t segTo = to[i];
  446. real_t boxBegin = _position[i];
  447. real_t boxEnd = boxBegin + _size[i];
  448. real_t cmin, cmax;
  449. if (segFrom < segTo)
  450. {
  451. if (segFrom > boxEnd || segTo < boxBegin)
  452. {
  453. return false;
  454. }
  455. real_t length = segTo - segFrom;
  456. cmin = segFrom < boxBegin ? (boxBegin - segFrom) / length : 0f;
  457. cmax = segTo > boxEnd ? (boxEnd - segFrom) / length : 1f;
  458. }
  459. else
  460. {
  461. if (segTo > boxEnd || segFrom < boxBegin)
  462. {
  463. return false;
  464. }
  465. real_t length = segTo - segFrom;
  466. cmin = segFrom > boxEnd ? (boxEnd - segFrom) / length : 0f;
  467. cmax = segTo < boxBegin ? (boxBegin - segFrom) / length : 1f;
  468. }
  469. if (cmin > min)
  470. {
  471. min = cmin;
  472. }
  473. if (cmax < max)
  474. {
  475. max = cmax;
  476. }
  477. if (max < min)
  478. {
  479. return false;
  480. }
  481. }
  482. return true;
  483. }
  484. /// <summary>
  485. /// Returns a larger AABB that contains this AABB and `b`.
  486. /// </summary>
  487. /// <param name="with">The other AABB.</param>
  488. /// <returns>The merged AABB.</returns>
  489. public AABB Merge(AABB with)
  490. {
  491. Vector3 beg1 = _position;
  492. Vector3 beg2 = with._position;
  493. var end1 = new Vector3(_size.x, _size.y, _size.z) + beg1;
  494. var end2 = new Vector3(with._size.x, with._size.y, with._size.z) + beg2;
  495. var min = new Vector3(
  496. beg1.x < beg2.x ? beg1.x : beg2.x,
  497. beg1.y < beg2.y ? beg1.y : beg2.y,
  498. beg1.z < beg2.z ? beg1.z : beg2.z
  499. );
  500. var max = new Vector3(
  501. end1.x > end2.x ? end1.x : end2.x,
  502. end1.y > end2.y ? end1.y : end2.y,
  503. end1.z > end2.z ? end1.z : end2.z
  504. );
  505. return new AABB(min, max - min);
  506. }
  507. /// <summary>
  508. /// Constructs an AABB from a position and size.
  509. /// </summary>
  510. /// <param name="position">The position.</param>
  511. /// <param name="size">The size, typically positive.</param>
  512. public AABB(Vector3 position, Vector3 size)
  513. {
  514. _position = position;
  515. _size = size;
  516. }
  517. /// <summary>
  518. /// Constructs an AABB from a position, width, height, and depth.
  519. /// </summary>
  520. /// <param name="position">The position.</param>
  521. /// <param name="width">The width, typically positive.</param>
  522. /// <param name="height">The height, typically positive.</param>
  523. /// <param name="depth">The depth, typically positive.</param>
  524. public AABB(Vector3 position, real_t width, real_t height, real_t depth)
  525. {
  526. _position = position;
  527. _size = new Vector3(width, height, depth);
  528. }
  529. /// <summary>
  530. /// Constructs an AABB from x, y, z, and size.
  531. /// </summary>
  532. /// <param name="x">The position's X coordinate.</param>
  533. /// <param name="y">The position's Y coordinate.</param>
  534. /// <param name="z">The position's Z coordinate.</param>
  535. /// <param name="size">The size, typically positive.</param>
  536. public AABB(real_t x, real_t y, real_t z, Vector3 size)
  537. {
  538. _position = new Vector3(x, y, z);
  539. _size = size;
  540. }
  541. /// <summary>
  542. /// Constructs an AABB from x, y, z, width, height, and depth.
  543. /// </summary>
  544. /// <param name="x">The position's X coordinate.</param>
  545. /// <param name="y">The position's Y coordinate.</param>
  546. /// <param name="z">The position's Z coordinate.</param>
  547. /// <param name="width">The width, typically positive.</param>
  548. /// <param name="height">The height, typically positive.</param>
  549. /// <param name="depth">The depth, typically positive.</param>
  550. public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth)
  551. {
  552. _position = new Vector3(x, y, z);
  553. _size = new Vector3(width, height, depth);
  554. }
  555. public static bool operator ==(AABB left, AABB right)
  556. {
  557. return left.Equals(right);
  558. }
  559. public static bool operator !=(AABB left, AABB right)
  560. {
  561. return !left.Equals(right);
  562. }
  563. public override bool Equals(object obj)
  564. {
  565. if (obj is AABB)
  566. {
  567. return Equals((AABB)obj);
  568. }
  569. return false;
  570. }
  571. public bool Equals(AABB other)
  572. {
  573. return _position == other._position && _size == other._size;
  574. }
  575. /// <summary>
  576. /// Returns true if this AABB and `other` are approximately equal, by running
  577. /// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component.
  578. /// </summary>
  579. /// <param name="other">The other AABB to compare.</param>
  580. /// <returns>Whether or not the AABBs are approximately equal.</returns>
  581. public bool IsEqualApprox(AABB other)
  582. {
  583. return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size);
  584. }
  585. public override int GetHashCode()
  586. {
  587. return _position.GetHashCode() ^ _size.GetHashCode();
  588. }
  589. public override string ToString()
  590. {
  591. return $"{_position}, {_size}";
  592. }
  593. public string ToString(string format)
  594. {
  595. return $"{_position.ToString(format)}, {_size.ToString(format)}";
  596. }
  597. }
  598. }