Line data Source code
1 : #include "MathUtils.hpp"
2 :
3 : #include <algorithm>
4 : #include <cmath>
5 : #include <numbers>
6 : #include <numeric>
7 : #include <ostream>
8 : #include <random>
9 :
10 0 : sf::Time operator*(const sf::Time& time, double factor)
11 : {
12 0 : return time * static_cast<float>(factor);
13 : }
14 :
15 2 : std::ostream& operator<<(std::ostream& os, const sf::Vector2d& v)
16 : {
17 2 : return os << "(" << v.x << ", " << v.y << ")";
18 : }
19 :
20 7 : double operator*(const sf::Vector2d& a, const sf::Vector2d& b)
21 : {
22 7 : return a.x * b.x + a.y * b.y;
23 : }
24 :
25 : namespace cell::mathutils
26 : {
27 :
28 10 : double abs(const sf::Vector2d& vec)
29 : {
30 10 : return std::hypot(vec.x, vec.y);
31 : }
32 :
33 0 : sf::Vector2d calculateNormal(const sf::Vector2d& v1, const sf::Vector2d& v2)
34 : {
35 0 : const auto diff = v2 - v1;
36 :
37 0 : return diff / abs(diff);
38 : }
39 :
40 3 : std::vector<sf::Vector2d> calculateGrid(double width, double height, double edgeLength)
41 : {
42 3 : static std::random_device rd;
43 3 : static std::mt19937 gen(rd());
44 :
45 3 : std::vector<sf::Vector2d> gridPoints;
46 3 : gridPoints.reserve(static_cast<std::size_t>((static_cast<double>(width) / edgeLength) *
47 3 : (static_cast<double>(height) / edgeLength)));
48 3 : double spacing = edgeLength + 1;
49 :
50 835 : for (int i = 0; i < static_cast<int>(width / spacing); ++i)
51 : {
52 463166 : for (int j = 0; j < static_cast<int>(height / spacing); ++j)
53 462334 : gridPoints.emplace_back(spacing * static_cast<double>(i + 1), spacing * static_cast<double>(j + 1));
54 : }
55 :
56 3 : std::shuffle(gridPoints.begin(), gridPoints.end(), gen);
57 :
58 3 : return gridPoints;
59 0 : }
60 :
61 0 : bool pointIsInCircle(const sf::Vector2d& point, const sf::Vector2d& M, double R)
62 : {
63 0 : const auto diff = point - M;
64 :
65 0 : return diff.x * diff.x + diff.y * diff.y < R * R;
66 : }
67 :
68 462896 : bool circleIsFullyContainedByCircle(const sf::Vector2d& M1, double R1, const sf::Vector2d& M2, double R2)
69 : {
70 462896 : const auto diff = M1 - M2;
71 :
72 462896 : return diff.x * diff.x + diff.y * diff.y < (R2 - R1) * (R2 - R1);
73 : }
74 :
75 362181 : bool circlesOverlap(const sf::Vector2d& M1, double R1, const sf::Vector2d& M2, double R2)
76 : {
77 362181 : return circlesOverlap(M1, R1, M2, R2, MinOverlap{0.0});
78 : }
79 :
80 362195 : bool circlesOverlap(const sf::Vector2d& M1, double R1, const sf::Vector2d& M2, double R2, MinOverlap minOverlap)
81 : {
82 362195 : const auto diff = M1 - M2;
83 362195 : const double R = R1 + R2 - minOverlap.value;
84 :
85 362195 : return diff.x * diff.x + diff.y * diff.y <= R * R;
86 : }
87 :
88 16 : bool circlesIntersect(const sf::Vector2d& M1, double R1, const sf::Vector2d& M2, double R2)
89 : {
90 : // equivalent to: return circlesOverlap(...) && !circleIsFullyContainedByCircle(...)
91 16 : const auto diff = M1 - M2;
92 16 : const auto distanceSquared = diff.x * diff.x + diff.y * diff.y;
93 :
94 16 : return (distanceSquared <= (R1 + R2) * (R1 + R2)) && distanceSquared >= (R2 - R1) * (R2 - R1);
95 : }
96 :
97 0 : bool isMovingTowards(const sf::Vector2d& pos1, const sf::Vector2d& velocity, const sf::Vector2d& point)
98 : {
99 0 : const auto diff = point - pos1;
100 :
101 0 : return velocity * diff > 0;
102 : }
103 :
104 0 : double calculateOverlap(const sf::Vector2d& r, double R1, double R2)
105 : {
106 0 : double distance = mathutils::abs(r);
107 :
108 0 : return R1 + R2 - distance;
109 : }
110 :
111 2 : double getAngleBetween(const sf::Vector2d& a, const sf::Vector2d& b)
112 : {
113 2 : const double lenA = abs(a);
114 2 : const double lenB = abs(b);
115 :
116 2 : if (lenA == 0.0 || lenB == 0.0)
117 0 : return 0.0; // arbitrary, no direction
118 :
119 2 : double dot = a * b / (lenA * lenB);
120 :
121 : // Clamp to valid range for acos
122 2 : dot = std::clamp(dot, -1.0, 1.0);
123 :
124 2 : return std::acos(dot) * 180.0 / std::numbers::pi;
125 : }
126 :
127 : } // namespace cell::mathutils
|