common.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. //
  2. // common.cpp
  3. // math
  4. //
  5. // Created by Sam Jaffe on 8/20/16.
  6. //
  7. #include "game/math/common.hpp"
  8. #include <vector>
  9. #include "game/math/angle.hpp"
  10. #include "game/math/compare.hpp"
  11. #include "game/math/shape.hpp"
  12. namespace math {
  13. vec2 rotate(vec2 const & c, vec2 const & p, radian r) {
  14. vec2 trans = p - c;
  15. vec2 vcos = trans * static_cast<float>(cos(r));
  16. vec2 vsin = trans * static_cast<float>(sin(r));
  17. return {{
  18. vcos[0] - vsin[1] + c[0],
  19. vsin[0] - vcos[1] + c[1]
  20. }};
  21. }
  22. dim2::quad rotate(vec2 const & c, dim2::quad const & q, radian r) {
  23. return {
  24. rotate(c, q.ll, r),
  25. rotate(c, q.lr, r),
  26. rotate(c, q.ur, r),
  27. rotate(c, q.ul, r)
  28. };
  29. }
  30. enum orientation {
  31. colinear = 0, clockwise = 1, anticlockwise = 2
  32. };
  33. orientation orient(dim2::point const & p, dim2::point const & q,
  34. dim2::point const & r) {
  35. float val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
  36. if (val == 0) return colinear;
  37. return (val > 0) ? clockwise : anticlockwise;
  38. }
  39. bool contains(dim2::line const & ln, dim2::point const & pt) {
  40. auto xs = std::minmax(ln.first[0], ln.second[0], lessinf());
  41. auto ys = std::minmax(ln.first[1], ln.second[1], lessinf());
  42. return orient(ln.first, ln.second, pt) == colinear &&
  43. between(pt[0], xs.first, xs.second) &&
  44. between(pt[1], ys.first, ys.second);
  45. }
  46. bool contains(dim2::circle const & shape, dim2::point const & pt) {
  47. vec2 const delta = pt - shape.center;
  48. return delta.dot(delta) <= std::pow(shape.radius, 2);
  49. }
  50. static dim2::line ray_x(dim2::point const & pt, dim2::line const & l) {
  51. auto x_inf = std::max({l.first[0], l.second[0], pt[0]});
  52. return {pt, {{x_inf, pt[1]}}};
  53. }
  54. static bool contains(std::vector<dim2::line> const & segments,
  55. dim2::point const & pt) {
  56. int hits = 0;
  57. for (auto l : segments) {
  58. if (contains(l, pt)) return true;
  59. else if (intersects(l, ray_x(pt, l))) ++hits;
  60. }
  61. return (hits & 1) == 1;
  62. }
  63. bool contains(dim2::quad const & shape, dim2::point const & pt) {
  64. return contains(shapes::segments(shape), pt);
  65. }
  66. bool intersects(dim2::line const & lhs, dim2::line const & rhs) {
  67. // Find the four orientations needed for general and
  68. // special cases
  69. orientation o1 = orient(lhs.first, lhs.second, rhs.first);
  70. orientation o2 = orient(lhs.first, lhs.second, rhs.second);
  71. orientation o3 = orient(rhs.first, rhs.second, lhs.first);
  72. orientation o4 = orient(rhs.first, rhs.second, lhs.second);
  73. // General case
  74. if (o1 != o2 && o3 != o4)
  75. return true;
  76. // Special Cases
  77. // p1, q1 and p2 are colinear and p2 lies on segment p1q1
  78. if (o1 == colinear && contains(lhs, rhs.second)) { return true; }
  79. // p1, q1 and q2 are colinear and q2 lies on segment p1q1
  80. if (o2 == colinear && contains(lhs, rhs.second)) { return true; }
  81. // p2, q2 and p1 are colinear and p1 lies on segment p2q2
  82. if (o3 == colinear && contains(rhs, lhs.first)) { return true; }
  83. // p2, q2 and q1 are colinear and q1 lies on segment p2q2
  84. if (o4 == colinear && contains(rhs, lhs.second)) { return true; }
  85. return false; // Doesn't fall in any of the above cases
  86. }
  87. bool intersects(dim2::line const & lhs, dim2::circle const & rhs) {
  88. dim2::line const orth = lines::orthogonal(lhs, rhs.center);
  89. vec2 const delta = orth.second - orth.first;
  90. return delta.dot(delta) <= std::pow(rhs.radius, 2);
  91. }
  92. bool intersects(dim2::line const & lhs, dim2::quad const & rhs) {
  93. std::vector<dim2::line> segments = shapes::segments(rhs);
  94. auto lhs_intersects = [&lhs](dim2::line const & ln) {
  95. return intersects(lhs, ln);
  96. };
  97. return std::any_of(segments.begin(), segments.end(), lhs_intersects) ||
  98. contains(segments, lhs.first) ||
  99. contains(segments, lhs.second);
  100. }
  101. bool intersects(dim2::quad const & lhs, dim2::circle const & rhs) {
  102. std::vector<dim2::line> segments = shapes::segments(lhs);
  103. auto rhs_intersects = [&rhs](dim2::line const & ln) {
  104. return intersects(ln, rhs);
  105. };
  106. return std::any_of(segments.begin(), segments.end(), rhs_intersects) ||
  107. contains(lhs, rhs.center);
  108. }
  109. bool intersects(dim2::quad const & lhs, dim2::quad const & rhs);
  110. bool intersects(dim2::circle const & lhs, dim2::circle const & rhs) {
  111. vec2 const delta = rhs.center - lhs.center;
  112. return delta.dot(delta) <= std::pow(lhs.radius + rhs.radius, 2);
  113. }
  114. }