Math.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #include "Math.h"
  2. #include <list>
  3. #include <assert.h>
  4. #include <cmath>
  5. using namespace ltbl;
  6. sf::Vector2f ltbl::rectCenter(const sf::FloatRect &rect) {
  7. return sf::Vector2f(rect.left + rect.width * 0.5f, rect.top + rect.height * 0.5f);
  8. }
  9. bool ltbl::rectIntersects(const sf::FloatRect &rect, const sf::FloatRect &other) {
  10. if (rect.left + rect.width < other.left)
  11. return false;
  12. if (rect.top + rect.height < other.top)
  13. return false;
  14. if (rect.left > other.left + other.width)
  15. return false;
  16. if (rect.top > other.top + other.height)
  17. return false;
  18. return true;
  19. }
  20. bool ltbl::rectContains(const sf::FloatRect &rect, const sf::FloatRect &other) {
  21. if (other.left < rect.left)
  22. return false;
  23. if (other.top < rect.top)
  24. return false;
  25. if (other.left + other.width > rect.left + rect.width)
  26. return false;
  27. if (other.top + other.height > rect.top + rect.height)
  28. return false;
  29. return true;
  30. }
  31. sf::Vector2f ltbl::rectHalfDims(const sf::FloatRect &rect) {
  32. return sf::Vector2f(rect.width * 0.5f, rect.height * 0.5f);
  33. }
  34. sf::Vector2f ltbl::rectDims(const sf::FloatRect &rect) {
  35. return sf::Vector2f(rect.width, rect.height);
  36. }
  37. sf::Vector2f ltbl::rectLowerBound(const sf::FloatRect &rect) {
  38. return sf::Vector2f(rect.left, rect.top);
  39. }
  40. sf::Vector2f ltbl::rectUpperBound(const sf::FloatRect &rect) {
  41. return sf::Vector2f(rect.left + rect.width, rect.top + rect.height);
  42. }
  43. sf::FloatRect ltbl::rectFromBounds(const sf::Vector2f &lowerBound, const sf::Vector2f &upperBound) {
  44. return sf::FloatRect(lowerBound.x, lowerBound.y, upperBound.x - lowerBound.x, upperBound.y - lowerBound.y);
  45. }
  46. float ltbl::vectorMagnitude(const sf::Vector2f &vector) {
  47. return std::sqrt(vector.x * vector.x + vector.y * vector.y);
  48. }
  49. float ltbl::vectorMagnitudeSquared(const sf::Vector2f &vector) {
  50. return vector.x * vector.x + vector.y * vector.y;
  51. }
  52. sf::Vector2f ltbl::vectorNormalize(const sf::Vector2f &vector) {
  53. float magnitude = vectorMagnitude(vector);
  54. if (magnitude == 0.0f)
  55. return sf::Vector2f(1.0f, 0.0f);
  56. float distInv = 1.0f / magnitude;
  57. return sf::Vector2f(vector.x * distInv, vector.y * distInv);
  58. }
  59. float ltbl::vectorProject(const sf::Vector2f &left, const sf::Vector2f &right) {
  60. assert(vectorMagnitudeSquared(right) != 0.0f);
  61. return vectorDot(left, right) / vectorMagnitudeSquared(right);
  62. }
  63. sf::FloatRect ltbl::rectRecenter(const sf::FloatRect &rect, const sf::Vector2f &center) {
  64. sf::Vector2f dims = rectDims(rect);
  65. return sf::FloatRect(center - rectHalfDims(rect), dims);
  66. }
  67. float ltbl::vectorDot(const sf::Vector2f &left, const sf::Vector2f &right) {
  68. return left.x * right.x + left.y * right.y;
  69. }
  70. sf::FloatRect ltbl::rectExpand(const sf::FloatRect &rect, const sf::Vector2f &point) {
  71. sf::Vector2f lowerBound = rectLowerBound(rect);
  72. sf::Vector2f upperBound = rectUpperBound(rect);
  73. if (point.x < lowerBound.x)
  74. lowerBound.x = point.x;
  75. else if (point.x > upperBound.x)
  76. upperBound.x = point.x;
  77. if (point.y < lowerBound.y)
  78. lowerBound.y = point.y;
  79. else if (point.y > upperBound.y)
  80. upperBound.y = point.y;
  81. return rectFromBounds(lowerBound, upperBound);
  82. }
  83. bool ltbl::shapeIntersection(const sf::ConvexShape &left, const sf::ConvexShape &right) {
  84. std::vector<sf::Vector2f> transformedLeft(left.getPointCount());
  85. for (unsigned i = 0; i < left.getPointCount(); i++)
  86. transformedLeft[i] = left.getTransform().transformPoint(left.getPoint(i));
  87. std::vector<sf::Vector2f> transformedRight(right.getPointCount());
  88. for (unsigned i = 0; i < right.getPointCount(); i++)
  89. transformedRight[i] = right.getTransform().transformPoint(right.getPoint(i));
  90. for (unsigned i = 0; i < left.getPointCount(); i++) {
  91. sf::Vector2f point = transformedLeft[i];
  92. sf::Vector2f nextPoint;
  93. if (i == left.getPointCount() - 1u)
  94. nextPoint = transformedLeft[0];
  95. else
  96. nextPoint = transformedLeft[i + 1];
  97. sf::Vector2f edge = nextPoint - point;
  98. // Project points from other shape onto perpendicular
  99. sf::Vector2f edgePerpendicular = sf::Vector2f(edge.y, -edge.x);
  100. float pointProj = vectorProject(point, edgePerpendicular);
  101. float minRightProj = vectorProject(transformedRight[0], edgePerpendicular);
  102. for (unsigned j = 1; j < right.getPointCount(); j++) {
  103. float proj = vectorProject(transformedRight[j], edgePerpendicular);
  104. minRightProj = std::min(minRightProj, proj);
  105. }
  106. if (minRightProj > pointProj)
  107. return false;
  108. }
  109. for (unsigned i = 0; i < right.getPointCount(); i++) {
  110. sf::Vector2f point = transformedRight[i];
  111. sf::Vector2f nextPoint;
  112. if (i == right.getPointCount() - 1u)
  113. nextPoint = transformedRight[0];
  114. else
  115. nextPoint = transformedRight[i + 1];
  116. sf::Vector2f edge = nextPoint - point;
  117. // Project points from other shape onto perpendicular
  118. sf::Vector2f edgePerpendicular = sf::Vector2f(edge.y, -edge.x);
  119. float pointProj = vectorProject(point, edgePerpendicular);
  120. float minRightProj = vectorProject(transformedLeft[0], edgePerpendicular);
  121. for (unsigned j = 1; j < left.getPointCount(); j++) {
  122. float proj = vectorProject(transformedLeft[j], edgePerpendicular);
  123. minRightProj = std::min(minRightProj, proj);
  124. }
  125. if (minRightProj > pointProj)
  126. return false;
  127. }
  128. return true;
  129. }
  130. sf::ConvexShape ltbl::shapeFromRect(const sf::FloatRect &rect) {
  131. sf::ConvexShape shape(4);
  132. sf::Vector2f halfDims = rectHalfDims(rect);
  133. shape.setPoint(0, sf::Vector2f(-halfDims.x, -halfDims.y));
  134. shape.setPoint(1, sf::Vector2f(halfDims.x, -halfDims.y));
  135. shape.setPoint(2, sf::Vector2f(halfDims.x, halfDims.y));
  136. shape.setPoint(3, sf::Vector2f(-halfDims.x, halfDims.y));
  137. shape.setPosition(rectCenter(rect));
  138. return shape;
  139. }
  140. sf::ConvexShape ltbl::shapeFixWinding(const sf::ConvexShape &shape) {
  141. sf::Vector2f center = sf::Vector2f(0.0f, 0.0f);
  142. std::list<sf::Vector2f> points;
  143. for (unsigned i = 0; i < shape.getPointCount(); i++) {
  144. points.push_back(shape.getPoint(i));
  145. center += shape.getPoint(i);
  146. }
  147. center /= static_cast<float>(shape.getPointCount());
  148. // Fix winding
  149. sf::Vector2f lastPoint = points.front();
  150. points.pop_front();
  151. std::vector<sf::Vector2f> fixedPoints;
  152. fixedPoints.push_back(lastPoint);
  153. while (fixedPoints.size() < shape.getPointCount()) {
  154. sf::Vector2f centerToLastPoint = lastPoint - center;
  155. sf::Vector2f lastPointDirection = ltbl::vectorNormalize(sf::Vector2f(-centerToLastPoint.y, centerToLastPoint.x));
  156. float maxD = -999999.0f;
  157. std::list<sf::Vector2f>::iterator nextPointIt;
  158. // Get next point
  159. for (std::list<sf::Vector2f>::iterator it = points.begin(); it != points.end(); it++) {
  160. sf::Vector2f toPointNormalized = ltbl::vectorNormalize(*it - lastPoint);
  161. float d = ltbl::vectorDot(toPointNormalized, lastPointDirection);
  162. if (d > maxD) {
  163. maxD = d;
  164. nextPointIt = it;
  165. }
  166. }
  167. fixedPoints.push_back(*nextPointIt);
  168. points.erase(nextPointIt);
  169. }
  170. sf::ConvexShape fixedShape(shape.getPointCount());
  171. for (unsigned i = 0; i < shape.getPointCount(); i++)
  172. fixedShape.setPoint(i, fixedPoints[i]);
  173. return fixedShape;
  174. }
  175. bool ltbl::rayIntersect(const sf::Vector2f &as, const sf::Vector2f &ad, const sf::Vector2f &bs, const sf::Vector2f &bd, sf::Vector2f &intersection) {
  176. float dx = bs.x - as.x;
  177. float dy = bs.y - as.y;
  178. float det = bd.x * ad.y - bd.y * ad.x;
  179. if (det == 0.0f)
  180. return false;
  181. float u = (dy * bd.x - dx * bd.y) / det;
  182. if (u < 0.0f)
  183. return false;
  184. float v = (dy * ad.x - dx * ad.y) / det;
  185. if (v < 0.0f)
  186. return false;
  187. intersection = as + ad * u;
  188. return true;
  189. }